Visual Studio LightSwitch 2015 [Second Edition] 9781484207673, 9781484207666, 148420767X, 1484207661

In this fully updated second edition, award-winning author Tim Leung explains how to build data-centric business applica

456 120 93MB

English Pages 853 [859] Year 2015

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

Visual Studio LightSwitch 2015 [Second Edition]
 9781484207673, 9781484207666, 148420767X, 1484207661

Citation preview

T HE E X P ER T ’S VOICE ® I N .N E T

Visual Studio LightSwitch 2015 Create business applications easily, quickly, and effectively — Second Edition — Tim Leung

Visual Studio LightSwitch 2015 Second Edition

Tim Leung

Visual Studio LightSwitch 2015 Copyright © 2015 by Tim Leung 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. Exempted from this legal reservation are brief excerpts in connection with reviews or scholarly analysis or material supplied specifically for the purpose of being entered and executed on a computer system, for exclusive use by the purchaser of the work. Duplication of this publication or parts thereof is permitted only under the provisions of the Copyright Law of the Publisher’s location, in its current version, and permission for use must always be obtained from Springer. Permissions for use may be obtained through RightsLink at the Copyright Clearance Center. Violations are liable to prosecution under the respective Copyright Law. ISBN-13 (pbk): 978-1-4842-0767-3 ISBN-13 (electronic): 978-1-4842-0766-6 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: Welmoed Spahr Lead Editor: James DeWolf Development Editor: Douglas Pundick Technical Reviewer: Fabio Claudio Ferracchiati Editorial Board: Steve Anglin, Pramila Balen, Louise Corrigan, Jim DeWolf, Jonathan Gennick, Robert Hutchinson, Celestin Suresh John, Michelle Lowman, James Markham, Susan McDermott, Matthew Moodie, Jeffrey Pepper, Douglas Pundick, Ben Renow-Clarke, Gwenan Spearing Coordinating Editor: Melissa Maldonado Copy Editor: April Rondeau Compositor: SPi Global Indexer: SPi Global Artist: SPi Global Distributed to the book trade worldwide by Springer Science+Business Media New York, 233 Spring Street, 6th Floor, New York, NY 10013. Phone 1-800-SPRINGER, fax (201) 348-4505, email [email protected], or visit www.springer.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 email [email protected], or visit www.apress.com. Apress and friends of ED books 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 Special Bulk Sales–eBook Licensing web page at www.apress.com/bulk-sales. Any source code or other supplementary material referenced by the author in this text is available to readers at www.apress.com. For detailed information about how to locate your book’s source code, go to www.apress.com/source-code/.

Contents at a Glance About the Author��������������������������������������������������������������������������������������������������xxiii About the Technical Reviewers�����������������������������������������������������������������������������xxv Acknowledgments�����������������������������������������������������������������������������������������������xxvii Introduction����������������������������������������������������������������������������������������������������������xxix

■Part ■ I: Introducing LightSwitch���������������������������������������������������������� 1 ■Chapter ■ 1: Introducing LightSwitch����������������������������������������������������������������������� 3 ■Chapter ■ 2: Setting Up Your Data�������������������������������������������������������������������������� 15 ■Chapter ■ 3: Building HTML Applications��������������������������������������������������������������� 43 ■Chapter ■ 4: Creating Desktop Applications����������������������������������������������������������� 73

■Part ■ II: Working with Data�������������������������������������������������������������� 111 ■Chapter ■ 5: Quer ying Your Data�������������������������������������������������������������������������� 113 ■Chapter ■ 6: Writing Data-Access Code��������������������������������������������������������������� 129 ■Chapter ■ 7: Validating Data��������������������������������������������������������������������������������� 167

■Part ■ III: Writing ScreenCode����������������������������������������������������������� 201 ■Chapter ■ 8: Refinining HTML Clients Screens with JavaScript/CSS�������������������� 203 ■Chapter ■ 9: Enhancing Desktop Screens with .NET Code������������������������������������ 259

■Part ■ IV: Refining Your Application�������������������������������������������������� 303 ■Chapter ■ 10: Searching Data������������������������������������������������������������������������������� 305 ■Chapter ■ 11: Building Practical Application Features����������������������������������������� 329

iii

■ Contents at a Glance

■Chapter ■ 12: Supporting Multiple Languages����������������������������������������������������� 387 ■Chapter ■ 13: Creating and Using Custom Controls��������������������������������������������� 407

■Part ■ V: Extending the Reach of Your Data��������������������������������������� 441 ■Chapter ■ 14: Optimizing Data Connectivity with RIA Services��������������������������� 443 ■Chapter ■ 15: Sharing Data with OData���������������������������������������������������������������� 465

■Part ■ VI: Getting Data Out����������������������������������������������������������������� 483 ■Chapter ■ 16: Creating Reports���������������������������������������������������������������������������� 485 ■Chapter ■ 17: Generating Office Documents��������������������������������������������������������� 521 ■Chapter ■ 18: Sending Email�������������������������������������������������������������������������������� 561

■Part ■ VII: Extending LightSwitch������������������������������������������������������ 591 ■Chapter ■ 19: Creating Control Extensions����������������������������������������������������������� 593 ■Chapter ■ 20: Creating Data and Presentation Extensions����������������������������������� 655

■Part ■ VIII: Securing Your Application����������������������������������������������� 735 ■Chapter ■ 21: Authenticating Your Users������������������������������������������������������������� 737 ■Chapter ■ 22: Authorizing Your Users������������������������������������������������������������������ 751

■Part ■ IX: Going Live with Your Application��������������������������������������� 777 ■Chapter ■ 23: Deploying Applications������������������������������������������������������������������ 779 ■Appendix ■ A: Culture Names������������������������������������������������������������������������������� 811 ■Appendix ■ B: Data Type Identifiers��������������������������������������������������������������������� 817 ■Appendix ■ C: Using Properties in Custom Controls��������������������������������������������� 819 ■Appendix ■ D: Custom Screen Template View IDs ����������������������������������������������� 823 ■Appendix ■ E: Data Schemas�������������������������������������������������������������������������������� 827 Index��������������������������������������������������������������������������������������������������������������������� 841

iv

Contents About the Author��������������������������������������������������������������������������������������������������xxiii About the Technical Reviewers�����������������������������������������������������������������������������xxv Acknowledgments�����������������������������������������������������������������������������������������������xxvii Introduction����������������������������������������������������������������������������������������������������������xxix

■Part ■ I: Introducing LightSwitch���������������������������������������������������������� 1 ■Chapter ■ 1: Introducing LightSwitch����������������������������������������������������������������������� 3 What’s New in 2015��������������������������������������������������������������������������������������������������������� 3 Understanding LightSwitch’s Architecture����������������������������������������������������������������������� 4 The Data Tier������������������������������������������������������������������������������������������������������������������������������������������ 5 The Logic Tier����������������������������������������������������������������������������������������������������������������������������������������� 5 The Presentation Tier������������������������������������������������������������������������������������������������������������������������������ 6

Introducing the Model-Centric Architecture��������������������������������������������������������������������� 8 Building Your Application�������������������������������������������������������������������������������������������������� 9 Understanding MVVM (Model-View-ViewModel)������������������������������������������������������������ 10 Walkthrough: Creating a LightSwitch Project����������������������������������������������������������������� 10 Summary������������������������������������������������������������������������������������������������������������������������ 13 ■Chapter ■ 2: Setting Up Your Data�������������������������������������������������������������������������� 15 Choosing Where to Store Your Data�������������������������������������������������������������������������������� 15 What Are Entities and Properties?���������������������������������������������������������������������������������� 16 Creating Tables (Entities)������������������������������������������������������������������������������������������������ 16

v

■ Contents

Creating Fields (Properties)�������������������������������������������������������������������������������������������� 18 Storing Textual Data������������������������������������������������������������������������������������������������������������������������������ 18 Storing Numbers (Double and Decimal Types)������������������������������������������������������������������������������������� 19 Storing Numbers (Integer Types)���������������������������������������������������������������������������������������������������������� 19 Formatting Numeric Fields������������������������������������������������������������������������������������������������������������������� 19 Storing Images������������������������������������������������������������������������������������������������������������������������������������� 21 Storing Binary Data������������������������������������������������������������������������������������������������������������������������������ 21 Storing Dates ��������������������������������������������������������������������������������������������������������������������������������������� 21 Ensuring Unique Values������������������������������������������������������������������������������������������������������������������������ 22 Changing Data Types���������������������������������������������������������������������������������������������������������������������������� 22

Using LightSwitch Business Types��������������������������������������������������������������������������������� 23 Storing Email Addresses����������������������������������������������������������������������������������������������������������������������� 23 Storing Monetary Values����������������������������������������������������������������������������������������������������������������������� 23 Storing Phone Numbers������������������������������������������������������������������������������������������������������������������������ 25 Storing Web Addresses and Percentage Values����������������������������������������������������������������������������������� 26 Storing People Data������������������������������������������������������������������������������������������������������������������������������ 26

Examining What Happens in SQL Server������������������������������������������������������������������������ 26 Creating Choice Lists������������������������������������������������������������������������������������������������������ 27 Choice List Versus Related Tables�������������������������������������������������������������������������������������������������������� 28

Defining Relationships��������������������������������������������������������������������������������������������������� 28 Defining One-to-Many-Type Relationships������������������������������������������������������������������������������������������� 29 How Relationships Are Defined in SQL Server�������������������������������������������������������������������������������������� 30 Defining Self-Referencing Relationships���������������������������������������������������������������������������������������������� 31 Defining Many-to-Many Relationships������������������������������������������������������������������������������������������������� 31 Determining How Child Records Are Deleted��������������������������������������������������������������������������������������� 32

Attaching Existing Data�������������������������������������������������������������������������������������������������� 32 Attaching to an Existing Database�������������������������������������������������������������������������������������������������������� 34 Attaching to SharePoint Data��������������������������������������������������������������������������������������������������������������� 36 Deleting a Data Source������������������������������������������������������������������������������������������������������������������������� 37 Defining Relationships between Data Sources������������������������������������������������������������������������������������� 37

vi

■ Contents

Creating Computed Properties��������������������������������������������������������������������������������������� 37 Creating Summary Properties���������������������������������������������������������������������������������������� 37 Calculating Dates with Computed Properties��������������������������������������������������������������������������������������� 38 Summarizing Child Records with Computed Properties����������������������������������������������������������������������� 39 Returning Images with Computed Properties��������������������������������������������������������������������������������������� 40 Sorting and Filtering by Computed Properties�������������������������������������������������������������������������������������� 41

Summary������������������������������������������������������������������������������������������������������������������������ 41 ■Chapter ■ 3: Building HTML Applications��������������������������������������������������������������� 43 Building an HTML Application���������������������������������������������������������������������������������������� 43 Creating Screens���������������������������������������������������������������������������������������������������������������������������������� 43 Walkthrough 3-1. Creating an Application�������������������������������������������������������������������������������������������� 45

Using the Screen Designer��������������������������������������������������������������������������������������������� 53 Understanding Top-Level Screen Layout���������������������������������������������������������������������������������������������� 53 Using the Screen Designer Toolbar������������������������������������������������������������������������������������������������������� 55 Using Tabs ������������������������������������������������������������������������������������������������������������������������������������������� 55

Laying Out Your Screen with Group Controls������������������������������������������������������������������ 56 Using Data Controls�������������������������������������������������������������������������������������������������������� 58 Showing/Editing String Values������������������������������������������������������������������������������������������������������������� 58 Working with Boolean Values��������������������������������������������������������������������������������������������������������������� 60 Showing/Editing Date Values���������������������������������������������������������������������������������������������������������������� 60 Showing/Editing Email or Web Addresses�������������������������������������������������������������������������������������������� 61 Showing Lists of Records��������������������������������������������������������������������������������������������������������������������� 61 Using Data Picker Controls������������������������������������������������������������������������������������������������������������������� 64

Positioning Controls������������������������������������������������������������������������������������������������������� 64 Setting Screen Properties���������������������������������������������������������������������������������������������� 66 Building a Navigation Structure������������������������������������������������������������������������������������� 67 Setting a Home Screen������������������������������������������������������������������������������������������������������������������������� 67 Configuring the Navigation Menu��������������������������������������������������������������������������������������������������������� 68 Navigating to Different Screens ����������������������������������������������������������������������������������������������������������� 69

vii

■ Contents

Adding Navigation Buttons������������������������������������������������������������������������������������������������������������������� 70 Changing Button Icons������������������������������������������������������������������������������������������������������������������������� 70

Summary������������������������������������������������������������������������������������������������������������������������ 71 ■Chapter ■ 4: Creating Desktop Applications����������������������������������������������������������� 73 What This Chapter Covers���������������������������������������������������������������������������������������������� 73 What Are the Benefits of Desktop Applications?������������������������������������������������������������ 74 Creating a Desktop Client����������������������������������������������������������������������������������������������� 75 Setting the Application Type����������������������������������������������������������������������������������������������������������������� 75

Choosing a Screen Template������������������������������������������������������������������������������������������ 76 Walkthrough 4-1. Creating New Data Screens��������������������������������������������������������������� 77 Designing Screens��������������������������������������������������������������������������������������������������������� 78 Setting Screen Properties��������������������������������������������������������������������������������������������������������������������� 80 Grouping and Laying Out Controls�������������������������������������������������������������������������������������������������������� 80 Choosing Data Controls������������������������������������������������������������������������������������������������������������������������ 82 Displaying Data Using Data-Item Containers���������������������������������������������������������������������������������������� 84

Using Data-Selection Controls��������������������������������������������������������������������������������������� 85 Using the Auto-Complete Box Control�������������������������������������������������������������������������������������������������� 86 Using the Modal Window Picker Control����������������������������������������������������������������������������������������������� 87

Displaying Static Text and Images���������������������������������������������������������������������������������� 88 Setting Control Appearances������������������������������������������������������������������������������������������ 88 Positioning Control Labels�������������������������������������������������������������������������������������������������������������������� 90 Styling Labels and Static Text Controls������������������������������������������������������������������������������������������������� 91 Making Controls Read-Only������������������������������������������������������������������������������������������������������������������ 92

Including Related Data Items����������������������������������������������������������������������������������������� 93 Using the Data Grid and Data List Controls�������������������������������������������������������������������� 94 Creating an Editable Grid Screen����������������������������������������������������������������������������������� 95 Configuring Data Grid Settings������������������������������������������������������������������������������������������������������������� 96 Setting Data Grid Header Buttons��������������������������������������������������������������������������������������������������������� 98

Creating a List and Details Screen������������������������������������������������������������������������������� 100 Creating a Search Screen��������������������������������������������������������������������������������������������� 101 viii

■ Contents

Creating Details Screens���������������������������������������������������������������������������������������������� 102 Walkthrough 4-2. Using Details Screens�������������������������������������������������������������������������������������������� 103

Setting Application Properties�������������������������������������������������������������������������������������� 106 Configuring Screen Navigation������������������������������������������������������������������������������������� 107 Designing Screens at Runtime������������������������������������������������������������������������������������� 108 Reducing Project Sizes������������������������������������������������������������������������������������������������� 109 Summary���������������������������������������������������������������������������������������������������������������������� 109

■Part ■ II: Working with Data�������������������������������������������������������������� 111 ■Chapter ■ 5: Quer ying Your Data�������������������������������������������������������������������������� 113 Introduction to Data Retrieval��������������������������������������������������������������������������������������� 113 LightSwitch Queries Always Return Entities��������������������������������������������������������������������������������������� 113

Understanding the Query Pipeline�������������������������������������������������������������������������������� 114 Using LightSwitch’s Default Queries���������������������������������������������������������������������������� 115 Filtering and Sorting data��������������������������������������������������������������������������������������������� 116 Creating Queries Based on Entities���������������������������������������������������������������������������������������������������� 116 Applying Filters����������������������������������������������������������������������������������������������������������������������������������� 117 Comparing Against Other Fields/Properties���������������������������������������������������������������������������������������� 119 Passing Arguments into a Query�������������������������������������������������������������������������������������������������������� 120 Filtering by Global Values������������������������������������������������������������������������������������������������������������������� 120 Modifying Screen Queries������������������������������������������������������������������������������������������������������������������ 121

Sorting Data����������������������������������������������������������������������������������������������������������������� 121 Sorting Data Grids in Desktop Applications���������������������������������������������������������������������������������������� 122 Examining User-Setting Files�������������������������������������������������������������������������������������������������������������� 123

Walkthrough: Working with Queries����������������������������������������������������������������������������� 124 5-1. Filtering Controls������������������������������������������������������������������������������������������������������������������������� 124 5-2. Using Queries on Screens����������������������������������������������������������������������������������������������������������� 126

Summary���������������������������������������������������������������������������������������������������������������������� 127

ix

■ Contents

■Chapter ■ 6: Writing Data-Access Code��������������������������������������������������������������� 129 LightSwitch Data API���������������������������������������������������������������������������������������������������� 129 Retrieving Single Records by ID Value������������������������������������������������������������������������������������������������ 130 Working with Records and Nullable Data Types��������������������������������������������������������������������������������� 131 Using JavaScript Promises����������������������������������������������������������������������������������������������������������������� 132 Walkthrough 6-1: Client-Side Data-Access Code������������������������������������������������������������������������������� 133 Executing Queries Remotely��������������������������������������������������������������������������������������������������������������� 144

Working with the Save Pipeline������������������������������������������������������������������������������������ 146 Walkthrough 6-2: Working with Change Sets������������������������������������������������������������������������������������� 148

Managing Transactions in LightSwitch������������������������������������������������������������������������� 156 Understanding Transactions��������������������������������������������������������������������������������������������������������������� 156 Walkthrough 6-3: Creating Transactions in the Save Pipeline������������������������������������������������������������ 157

Understanding Concurrency����������������������������������������������������������������������������������������� 160 Displaying a Data-Conflict Screen������������������������������������������������������������������������������������������������������ 160 Walkthrough 6-4: Handling Conflicts in Code������������������������������������������������������������������������������������� 162

Summary���������������������������������������������������������������������������������������������������������������������� 164 ■Chapter ■ 7: Validating Data��������������������������������������������������������������������������������� 167 Understanding Validation in LightSwitch���������������������������������������������������������������������� 167 How Client Validation Works in Desktop Clients����������������������������������������������������������� 169 How MVVM Applies to Validation�������������������������������������������������������������������������������������������������������� 169

Defining Simple (Predefined) Validation Rules������������������������������������������������������������� 170 Writing Custom Property Validation������������������������������������������������������������������������������ 171 Identifying Where Validation Runs������������������������������������������������������������������������������������������������������ 171 Creating Validation Rules and Warnings��������������������������������������������������������������������������������������������� 172

Custom Validation Examples���������������������������������������������������������������������������������������� 174 Comparing against Other Properties�������������������������������������������������������������������������������������������������� 175 Mandating Data with Conditions�������������������������������������������������������������������������������������������������������� 176 Validating Patterns with Regular Expressions������������������������������������������������������������������������������������ 177 Checking against Child Collections���������������������������������������������������������������������������������������������������� 179

x

■ Contents

Validating Data on the Client���������������������������������������������������������������������������������������� 181 HTML Client Validation������������������������������������������������������������������������������������������������������������������������ 181 Desktop Client Validation�������������������������������������������������������������������������������������������������������������������� 186

Validating Data at the Database����������������������������������������������������������������������������������� 188 Walkthrough 7-1. Enforcing Data Rules����������������������������������������������������������������������� 189 Enforcing Uniqueness and Preventing Duplicates������������������������������������������������������������������������������ 189 Validating Deletions on the Server����������������������������������������������������������������������������������������������������� 192

Summary���������������������������������������������������������������������������������������������������������������������� 198

■Part ■ III: Writing ScreenCode����������������������������������������������������������� 201 ■Chapter ■ 8: Refinining HTML Clients Screens with JavaScript/CSS�������������������� 203 Examining the JavaScript API��������������������������������������������������������������������������������������� 203 Handling Screen Events���������������������������������������������������������������������������������������������������������������������� 203 API Objects����������������������������������������������������������������������������������������������������������������������������������������� 204

Performing Screen Tasks with JavaScript�������������������������������������������������������������������� 207 Setting Default Screen Values������������������������������������������������������������������������������������������������������������ 207 Hiding Controls and Setting Screen Titles������������������������������������������������������������������������������������������ 209

Displaying Custom Content on Screens����������������������������������������������������������������������� 211 Adding Custom Text on Screens��������������������������������������������������������������������������������������������������������� 211 Adding Custom HTML to Screens������������������������������������������������������������������������������������������������������� 213

Using Popups��������������������������������������������������������������������������������������������������������������� 214 Walkthrough 8-1. Confirming Actions with Popups���������������������������������������������������������������������������� 214

Using Data-Binding Techniques����������������������������������������������������������������������������������� 217 Formatting Data���������������������������������������������������������������������������������������������������������������������������������� 217 Running Code When Data Changes���������������������������������������������������������������������������������������������������� 221

Using Custom Controls������������������������������������������������������������������������������������������������� 222 Displaying Data with Custom Controls����������������������������������������������������������������������������������������������� 223 Editing HTML Data with Custom Controls������������������������������������������������������������������������������������������� 226

Customizing the Appearance of Your Application��������������������������������������������������������� 229 Theming Your Application������������������������������������������������������������������������������������������������������������������� 229 Bespoke Customization���������������������������������������������������������������������������������������������������������������������� 231 xi

■ Contents

Walkthrough 8-2. Customizing the UI��������������������������������������������������������������������������� 250 Creating Custom Navigation��������������������������������������������������������������������������������������������������������������� 251 Creating Custom Buttons�������������������������������������������������������������������������������������������������������������������� 257

Summary���������������������������������������������������������������������������������������������������������������������� 257 ■Chapter ■ 9: Enhancing Desktop Screens with .NET Code������������������������������������ 259 Adding Code to Your Application���������������������������������������������������������������������������������� 259 General Methods�������������������������������������������������������������������������������������������������������������������������������� 260 Access Control Methods��������������������������������������������������������������������������������������������������������������������� 260 Collection Methods����������������������������������������������������������������������������������������������������������������������������� 260 Screen Property Methods������������������������������������������������������������������������������������������������������������������� 261

Working with Code and Data���������������������������������������������������������������������������������������� 261 Displaying Custom Text and Information�������������������������������������������������������������������������������������������� 262 Accessing Grid and List Values����������������������������������������������������������������������������������������������������������� 264 Setting the Screen Title in Code��������������������������������������������������������������������������������������������������������� 264

Setting Default Screen Values ������������������������������������������������������������������������������������� 265 Navigating Screens������������������������������������������������������������������������������������������������������ 267 Opening Screens from Buttons or Links��������������������������������������������������������������������������������������������� 267 Adding Unbound Auto-Complete Boxes���������������������������������������������������������������������������������������������� 270 Refreshing All Open Screens ������������������������������������������������������������������������������������������������������������� 271 Passing Arguments into Screens ������������������������������������������������������������������������������������������������������� 271

Showing MessageBox and InputBox alerts������������������������������������������������������������������ 274 Working with Controls�������������������������������������������������������������������������������������������������� 275 Finding Controls Using FindControl���������������������������������������������������������������������������������������������������� 275 Referencing the Underlying Silverlight Control����������������������������������������������������������������������������������� 279 Handling Silverlight Control Events���������������������������������������������������������������������������������������������������� 281

Working with Threads�������������������������������������������������������������������������������������������������� 283 Finding Out Which Thread Your Code Is Executing On������������������������������������������������������������������������ 285 Understanding When to Execute Code on a Different Thread������������������������������������������������������������� 285

Reacting to Data Changes�������������������������������������������������������������������������������������������� 288 Using PropertyChanged on a New Data Screen��������������������������������������������������������������������������������� 288 Using PropertyChanged on a Details Screen�������������������������������������������������������������������������������������� 291 xii

■ Contents

Walkthrough: Practical Screen Enhancements������������������������������������������������������������ 294 Creating a Continuous New Data Screen ������������������������������������������������������������������������������������������� 294 Designing an Add/Edit Screen������������������������������������������������������������������������������������������������������������ 295 Customizing Data-Grid Dialogs����������������������������������������������������������������������������������������������������������� 297

Summary���������������������������������������������������������������������������������������������������������������������� 301

■Part ■ IV: Refining Your Application����������������������������������������������������������� 303 ■Chapter ■ 10: Searching Data������������������������������������������������������������������������������� 305 An Overview of Built-In Search������������������������������������������������������������������������������������ 305 Walkthrough 10-1. Building Custom Search���������������������������������������������������������������� 306 Defining a Search Query��������������������������������������������������������������������������������������������������������������������� 306 Creating the Search Screen���������������������������������������������������������������������������������������������������������������� 307

Building Advanced Searches���������������������������������������������������������������������������������������� 308 Introducing LINQ��������������������������������������������������������������������������������������������������������������������������������� 308

Practical Querying Examples��������������������������������������������������������������������������������������� 311 Filtering by Related Child Items���������������������������������������������������������������������������������������������������������� 311 Exists, In��������������������������������������������������������������������������������������������������������������������������������������������� 313 Not Exists, Not In�������������������������������������������������������������������������������������������������������������������������������� 314 Filtering by Date Elements������������������������������������������������������������������������������������������������������������������ 315 Top N Records������������������������������������������������������������������������������������������������������������������������������������� 317

String-Matching Examples������������������������������������������������������������������������������������������� 318 Matching Non-Concurrent Words������������������������������������������������������������������������������������������������������� 318 Matching Multiple Words (Optionally)������������������������������������������������������������������������������������������������� 321 Case Sensitivity���������������������������������������������������������������������������������������������������������������������������������� 323 Phonetic Searching����������������������������������������������������������������������������������������������������������������������������� 323

Debugging Queries������������������������������������������������������������������������������������������������������� 326 Walkthrough 10-2. Opening a Search Screen�������������������������������������������������������������� 327 Summary���������������������������������������������������������������������������������������������������������������������� 328

xiii

■ Contents

■Chapter ■ 11: Building Practical Application Features����������������������������������������� 329 Working with Files�������������������������������������������������������������������������������������������������������� 329 Adding File Support to HTML Client Applications������������������������������������������������������������������������������� 330 Adding File Support to Desktop Client Applications��������������������������������������������������������������������������� 343 Validating File Sizes���������������������������������������������������������������������������������������������������������������������������� 352

Selecting Multiple Records������������������������������������������������������������������������������������������ 353 Assigning and Unassigning Self-Joined Data ������������������������������������������������������������� 360 Creating Screens to Work with Single-Row Tables ����������������������������������������������������� 364 Nesting Data-Selection Controls���������������������������������������������������������������������������������� 368 Working with Locations������������������������������������������������������������������������������������������������ 373 Picking Up GPS Locations������������������������������������������������������������������������������������������������������������������� 373 Integrating with Mapping Systems����������������������������������������������������������������������������������������������������� 376

Summarizing Data�������������������������������������������������������������������������������������������������������� 379 Showing Aggregate Counts/Sums/Averages ������������������������������������������������������������������������������������� 379 Querying Data Remotely �������������������������������������������������������������������������������������������������������������������� 382 Merging Data ������������������������������������������������������������������������������������������������������������������������������������� 383

Summary���������������������������������������������������������������������������������������������������������������������� 385 ■Chapter ■ 12: Supporting Multiple Languages����������������������������������������������������� 387 Introduction������������������������������������������������������������������������������������������������������������������ 387 Supported Languages������������������������������������������������������������������������������������������������������������������������� 388

Preparing an Application for Localization��������������������������������������������������������������������� 388 Localizing Server Objects��������������������������������������������������������������������������������������������� 389 Translating Table Field Names������������������������������������������������������������������������������������������������������������ 390 Testing a Localized Application���������������������������������������������������������������������������������������������������������� 392 Translating .NET Server Messages����������������������������������������������������������������������������������������������������� 393

Localizing HTML Client Resources������������������������������������������������������������������������������� 398 Localizing Screen Titles and Menu Items������������������������������������������������������������������������������������������� 398 Localizing JavaScript Messages��������������������������������������������������������������������������������������������������������� 400 Localizing Dates and Numbers����������������������������������������������������������������������������������������������������������� 401

xiv

■ Contents

Localizing Desktop Apps���������������������������������������������������������������������������������������������� 401 Localizing Screen Titles and Menu Items������������������������������������������������������������������������������������������� 401 Localizing Silverlight .NET Code��������������������������������������������������������������������������������������������������������� 403

Summary���������������������������������������������������������������������������������������������������������������������� 405 ■Chapter ■ 13: Creating and Using Custom Controls��������������������������������������������� 407 Using Custom Controls������������������������������������������������������������������������������������������������� 407 Specifying a Custom Control�������������������������������������������������������������������������������������������������������������� 408 Binding Data to Custom Controls�������������������������������������������������������������������������������������������������������� 410 Binding Data Collections to Custom Control��������������������������������������������������������������������������������������� 412 Converting Values When Data Binding������������������������������������������������������������������������������������������������ 414

Creating a Custom Silverlight Control�������������������������������������������������������������������������� 419 Understanding Dependency Properties���������������������������������������������������������������������������������������������� 419 Creating a New Control and Dependency Property���������������������������������������������������������������������������� 420 Binding Dependency Properties to the Data Context�������������������������������������������������������������������������� 427 Adding the Duration Control to a Screen�������������������������������������������������������������������������������������������� 429 Calling Custom Control Methods via Dependency Properties������������������������������������������������������������� 429

Calling Screen Code from a Custom Control���������������������������������������������������������������� 432 Summary���������������������������������������������������������������������������������������������������������������������� 438

■Part ■ V: Extending the Reach of Your Data��������������������������������������� 441 ■Chapter ■ 14: Optimizing Data Connectivity with RIA Services��������������������������� 443 The History behind RIA Services���������������������������������������������������������������������������������� 443 Creating an RIA Services Project���������������������������������������������������������������������������������� 444 Creating a New Project����������������������������������������������������������������������������������������������������������������������� 445 Creating an Entity Class���������������������������������������������������������������������������������������������������������������������� 445 Creating a Domain Service Class������������������������������������������������������������������������������������������������������� 448

Retrieving Data������������������������������������������������������������������������������������������������������������� 448 Retrieving a Connection String from web.config���������������������������������������������������������� 453 Updating Data��������������������������������������������������������������������������������������������������������������� 453

xv

■ Contents

Calling SQL Stored Procedures������������������������������������������������������������������������������������ 456 Consuming Your RIA Service���������������������������������������������������������������������������������������� 461 Summary���������������������������������������������������������������������������������������������������������������������� 463 ■Chapter ■ 15: Sharing Data with OData���������������������������������������������������������������� 465 Introduction������������������������������������������������������������������������������������������������������������������ 465 Using External Data Sources���������������������������������������������������������������������������������������� 465 Finding Third-Party Data Sources to Use�������������������������������������������������������������������������������������������� 466 Determining Connection Settings������������������������������������������������������������������������������������������������������� 466 Connecting to an OData Data Source������������������������������������������������������������������������������������������������� 468 Understanding Default Data-Source Options�������������������������������������������������������������������������������������� 469

Exposing Your LightSwitch Data Via OData������������������������������������������������������������������ 470 Finding Your Application’s Endpoint URL�������������������������������������������������������������������������������������������� 470 Querying OData����������������������������������������������������������������������������������������������������������������������������������� 471 Securing OData Feeds������������������������������������������������������������������������������������������������������������������������ 472

Consuming LightSwitch Data��������������������������������������������������������������������������������������� 472 Connecting to LightSwitch Data from Excel��������������������������������������������������������������������������������������� 472 Connecting to LightSwitch Data from .NET���������������������������������������������������������������������������������������� 473 Connecting to LightSwitch from Other Platforms������������������������������������������������������������������������������� 480

Summary���������������������������������������������������������������������������������������������������������������������� 481

■Part ■ VI: Getting Data Out����������������������������������������������������������������� 483 ■Chapter ■ 16: Creating Reports���������������������������������������������������������������������������� 485 Introduction to Reporting��������������������������������������������������������������������������������������������� 485 Using ASP.NET to Create Reports��������������������������������������������������������������������������������� 485 Showing Grid Data on a Web Form����������������������������������������������������������������������������������������������������� 486 Displaying Grids within Grids�������������������������������������������������������������������������������������������������������������� 490 Creating Charts����������������������������������������������������������������������������������������������������������������������������������� 492 Securing and Deploying Reports�������������������������������������������������������������������������������������������������������� 495

Using Microsoft Reporting Services����������������������������������������������������������������������������� 495 Installing Reporting Services�������������������������������������������������������������������������������������������������������������� 496 Installing the Report Designer Components��������������������������������������������������������������������������������������� 496 xvi

■ Contents

Creating Reports��������������������������������������������������������������������������������������������������������������������������������� 498 Deploying Reports������������������������������������������������������������������������������������������������������������������������������ 503

Using the Report Viewer Control���������������������������������������������������������������������������������� 505 Linking Reports from Desktop Applications����������������������������������������������������������������� 507 Opening Reports in a New Browser Window�������������������������������������������������������������������������������������� 507 Displaying Reports inside LightSwitch Screens��������������������������������������������������������������������������������� 509 Printing Reports���������������������������������������������������������������������������������������������������������������������������������� 515

Linking Reports from HTML Client Applications����������������������������������������������������������� 516 Displaying Content inside an iframe��������������������������������������������������������������������������������������������������� 516 Adding Hyperlinks������������������������������������������������������������������������������������������������������������������������������ 517

Summary���������������������������������������������������������������������������������������������������������������������� 518 ■Chapter ■ 17: Generating Office Documents��������������������������������������������������������� 521 Overview of Techniques����������������������������������������������������������������������������������������������� 521 Using the OpenXML SDK��������������������������������������������������������������������������������������������������������������������� 522 Performing COM Automation�������������������������������������������������������������������������������������������������������������� 539 Performing Mail Merges with Word���������������������������������������������������������������������������������������������������� 544

Creating Adobe PDF Documents����������������������������������������������������������������������������������� 555 Summary���������������������������������������������������������������������������������������������������������������������� 558 ■Chapter ■ 18: Sending Email�������������������������������������������������������������������������������� 561 Overview to Sending Email ����������������������������������������������������������������������������������������� 561 Sending Email Notifications����������������������������������������������������������������������������������������� 562 Using Configuration Settings to Save Credentials������������������������������������������������������������������������������ 562 Creating a Reusable Email Class�������������������������������������������������������������������������������������������������������� 563 Sending the Email ������������������������������������������������������������������������������������������������������������������������������ 567

Initiating Emails from LightSwitch Clients������������������������������������������������������������������� 570 Building an Email service������������������������������������������������������������������������������������������������������������������� 570 Sending Messages from HTML Client Applications���������������������������������������������������������������������������� 578 Sending Messages from Desktop Applications���������������������������������������������������������������������������������� 580

Sending Mail with Microsoft Outlook �������������������������������������������������������������������������� 585 Summary���������������������������������������������������������������������������������������������������������������������� 590 xvii

■ Contents

■Part ■ VII: Extending LightSwitch������������������������������������������������������ 591 ■Chapter ■ 19: Creating Control Extensions����������������������������������������������������������� 593 Using LightSwitch Extensions�������������������������������������������������������������������������������������� 593 Installing LightSwitch Extensions������������������������������������������������������������������������������������������������������� 593 Using the Many-to-Many Data Control����������������������������������������������������������������������������������������������� 596

Preparing Your Computer to Develop Extensions��������������������������������������������������������� 597 Understanding Custom Control Types�������������������������������������������������������������������������� 598 Creating Value Controls������������������������������������������������������������������������������������������������ 599 Specifying Which Data Types to Support�������������������������������������������������������������������������������������������� 601 Supporting the FindControl Method���������������������������������������������������������������������������������������������������� 601 Setting the Control Icon���������������������������������������������������������������������������������������������������������������������� 603 Optimizing Controls for Data-Grid Use������������������������������������������������������������������������������������������������ 603 Retrieving Height, Size, and Property Settings����������������������������������������������������������������������������������� 609

Running and Deploying Your Extension������������������������������������������������������������������������ 610 Setting Product/Installation Attributes������������������������������������������������������������������������������������������������ 611

Creating a Detail Control (ComboBox)�������������������������������������������������������������������������� 611 Setting the Control’s Metadata����������������������������������������������������������������������������������������������������������� 612 Finding the Summary Property for an Entity�������������������������������������������������������������������������������������� 620

Creating Custom Property Editors�������������������������������������������������������������������������������� 628 Customizing Visual Studio’s Property Editor��������������������������������������������������������������������������������������� 628 Preparing Your Project������������������������������������������������������������������������������������������������������������������������ 629 Creating a Custom Control Editor������������������������������������������������������������������������������������������������������� 630 Linking Your Property with the Editor������������������������������������������������������������������������������������������������� 639 Customizing the Runtime Designer���������������������������������������������������������������������������������������������������� 640

Creating a Group Control Extension����������������������������������������������������������������������������� 645 Setting the Visibility of Labels������������������������������������������������������������������������������������������������������������ 648

Creating a Command Control Extension����������������������������������������������������������������������� 649 Summary���������������������������������������������������������������������������������������������������������������������� 652

xviii

■ Contents

■Chapter ■ 20: Creating Data and Presentation Extensions����������������������������������� 655 Introduction������������������������������������������������������������������������������������������������������������������ 655 Creating a Business Type Extension����������������������������������������������������������������������������� 656 Associating Custom Controls with Business Types���������������������������������������������������������������������������� 657 Enforcing Validation���������������������������������������������������������������������������������������������������������������������������� 657 Associating Validation Logic with a Business Type����������������������������������������������������������������������������� 659 Defining Property Sheet Attributes����������������������������������������������������������������������������������������������������� 659 Applying Validation Logic�������������������������������������������������������������������������������������������������������������������� 660 Creating Custom Property Editor Windows����������������������������������������������������������������������������������������� 665 Using Your Business Type������������������������������������������������������������������������������������������������������������������� 674

Creating a Custom Shell Extension������������������������������������������������������������������������������ 675 Preparing Your Project������������������������������������������������������������������������������������������������������������������������ 675 Defining the Look of Your Shell����������������������������������������������������������������������������������������������������������� 676 Binding Data to Your Shell������������������������������������������������������������������������������������������������������������������ 680 Displaying Your Application’s Logo����������������������������������������������������������������������������������������������������� 681 Adding Code That Supports Our Custom Shell����������������������������������������������������������������������������������� 681 Managing Screens������������������������������������������������������������������������������������������������������������������������������ 700 Executing Commands������������������������������������������������������������������������������������������������������������������������� 701 Performing Navigation������������������������������������������������������������������������������������������������������������������������ 702 Persisting User Settings��������������������������������������������������������������������������������������������������������������������� 702 Setting the Name and Description������������������������������������������������������������������������������������������������������ 704 Using Your Custom Shell��������������������������������������������������������������������������������������������������������������������� 705

Creating a Custom Theme Extension���������������������������������������������������������������������������� 706 Applying a Different Font�������������������������������������������������������������������������������������������������������������������� 706 Setting Different Colors���������������������������������������������������������������������������������������������������������������������� 707

Creating a Screen Template Extension������������������������������������������������������������������������� 708 Setting Template Properties��������������������������������������������������������������������������������������������������������������� 709 Defining the Data-Source Type����������������������������������������������������������������������������������������������������������� 712 Generating Screen Controls���������������������������������������������������������������������������������������������������������������� 712 Generating Screen Code��������������������������������������������������������������������������������������������������������������������� 716 Creating More Complex Screen Templates����������������������������������������������������������������������������������������� 719 xix

■ Contents

Creating an HTML Screen Template Extension������������������������������������������������������������� 719 Creating a Data-Source Extension������������������������������������������������������������������������������� 724 Creating an Entity Class���������������������������������������������������������������������������������������������������������������������� 724 Creating the Data Service Class��������������������������������������������������������������������������������������������������������� 727 Using the Data-Source Extension������������������������������������������������������������������������������������������������������� 732

Summary���������������������������������������������������������������������������������������������������������������������� 733

■Part ■ VIII: Securing Your Application����������������������������������������������� 735 ■Chapter ■ 21: Authenticating Your Users������������������������������������������������������������� 737 Choosing an Authentication Method����������������������������������������������������������������������������� 737 No Authentication������������������������������������������������������������������������������������������������������������������������������� 738 Enabling Windows Authentication������������������������������������������������������������������������������������������������������ 739 Forms Authentication������������������������������������������������������������������������������������������������������������������������� 740

Understanding Where User Details Are Stored������������������������������������������������������������� 741 Changing the Password Complexity Rules����������������������������������������������������������������������������������������� 742 Changing Password Encryption Settings�������������������������������������������������������������������������������������������� 743 Sharing Forms Authentication Data with ASP.NET������������������������������������������������������������������������������ 744 Allowing Users to Log Out of Desktop Web Applications�������������������������������������������������������������������� 746

Summary���������������������������������������������������������������������������������������������������������������������� 749 ■Chapter ■ 22: Authorizing Your Users������������������������������������������������������������������ 751 Applying Permissions��������������������������������������������������������������������������������������������������� 751 Defining Permissions��������������������������������������������������������������������������������������������������� 753 Creating an Application Administrator�������������������������������������������������������������������������� 753 Managing Roles and Users������������������������������������������������������������������������������������������� 754 Debugging Permission Code�������������������������������������������������������������������������������������������������������������� 755

Securing Server Objects����������������������������������������������������������������������������������������������� 755 Applying Table-Level Access Control�������������������������������������������������������������������������������������������������� 755 Applying Query-Level Permissions����������������������������������������������������������������������������������������������������� 760

Securing Client Objects������������������������������������������������������������������������������������������������ 761 Securing HTML Client Applications����������������������������������������������������������������������������������������������������� 763

xx

■ Contents

Custom Authorization Examples����������������������������������������������������������������������������������� 764 Associating Logins with Your Data����������������������������������������������������������������������������������������������������� 764 Opening Screens Conditionally at Login��������������������������������������������������������������������������������������������� 768 Restricting Row-Level Access to Data������������������������������������������������������������������������������������������������ 771 Setting Screen Control Properties by Permission������������������������������������������������������������������������������� 772 Allowing Users to Bypass Validation��������������������������������������������������������������������������������������������������� 774

Summary���������������������������������������������������������������������������������������������������������������������� 775

■Part ■ IX: Going Live with Your Application��������������������������������������� 777 ■Chapter ■ 23: Deploying Applications������������������������������������������������������������������ 779 Getting Started with Deployment��������������������������������������������������������������������������������� 779 Choosing an Application Topology������������������������������������������������������������������������������������������������������ 780 Choosing Whether to Publish or Package������������������������������������������������������������������������������������������� 781 Setting Up Your Workstations������������������������������������������������������������������������������������������������������������� 781 Setting Up SQL Server������������������������������������������������������������������������������������������������������������������������ 782

Using the Publish Wizard���������������������������������������������������������������������������������������������� 782 Data Connections Page����������������������������������������������������������������������������������������������������������������������� 784 Prerequisites Page������������������������������������������������������������������������������������������������������������������������������ 786 Security Page������������������������������������������������������������������������������������������������������������������������������������� 787 Digital Signature/Certificate Page������������������������������������������������������������������������������������������������������ 787

Setting Up Your Web Server����������������������������������������������������������������������������������������� 789 Installing the .NET 4.6 Framework����������������������������������������������������������������������������������������������������� 789 Setting Up IIS on Windows Server 2012/2008������������������������������������������������������������������������������������ 789 Setting Up IIS on Windows 7 and Above��������������������������������������������������������������������������������������������� 791 Configuring the Web Deploy Tool�������������������������������������������������������������������������������������������������������� 791 Setting Up IIS Application Pools���������������������������������������������������������������������������������������������������������� 792 Configuring SQL Server for Windows Authentication������������������������������������������������������������������������� 794 Configuring Secure Sockets Layer (SSL)�������������������������������������������������������������������������������������������� 795

Installing the Packages������������������������������������������������������������������������������������������������ 795 Installing a Two-Tier Desktop Application������������������������������������������������������������������������������������������� 795 Installing a Three-Tier Application in IIS��������������������������������������������������������������������������������������������� 797

xxi

■ Contents

Three-Tier Manual Deployment������������������������������������������������������������������������������������ 799 Deploying Data������������������������������������������������������������������������������������������������������������� 799 Updating an Application����������������������������������������������������������������������������������������������� 800 Troubleshooting Deployment Errors����������������������������������������������������������������������������� 800 Tracing Your Application��������������������������������������������������������������������������������������������������������������������� 801

Deploying to Azure������������������������������������������������������������������������������������������������������� 803 Connecting Visual Studio to Azure������������������������������������������������������������������������������������������������������ 803 Selecting a Service Type��������������������������������������������������������������������������������������������������������������������� 804 Creating a Database��������������������������������������������������������������������������������������������������������������������������� 805 Completing the Publishing Process���������������������������������������������������������������������������������������������������� 806

Publishing to SharePoint���������������������������������������������������������������������������������������������� 807 Summary���������������������������������������������������������������������������������������������������������������������� 808 ■Appendix ■ A: Culture Names������������������������������������������������������������������������������� 811 ■Appendix ■ B: Data Type Identifiers��������������������������������������������������������������������� 817 ■Appendix ■ C: Using Properties in Custom Controls��������������������������������������������� 819 ■Appendix ■ D: Custom Screen Template View IDs ����������������������������������������������� 823 Desktop Client View IDs����������������������������������������������������������������������������������������������� 823 HTML Client View IDs��������������������������������������������������������������������������������������������������� 825 ■Appendix ■ E: Data Schemas�������������������������������������������������������������������������������� 827 Help Desk Tables ��������������������������������������������������������������������������������������������������������� 827 External Tables������������������������������������������������������������������������������������������������������������� 838 Database Diagram�������������������������������������������������������������������������������������������������������� 838 Index��������������������������������������������������������������������������������������������������������������������� 841

xxii

About the Author Tim Leung is a professional software developer based in England. For the past 15 years, he has specialized in enterprise application development using products from the Microsoft technology stack. In particular, he possesses deep knowledge of Microsoft LightSwitch, the Microsoft .NET Framework, and SQL Server. He is an active member of the U.K. developer community and often delivers presentations on technical topics. He is also a chartered member of the British Computer Society. He is passionate about the concept of rapid application development and was awarded the Microsoft Community Contributor Award in 2011 for contributions to the LightSwitch community.

xxiii

About the Technical Reviewers Fabio Claudio Ferracchiati is a senior consultant and a senior analyst/developer using Microsoft technologies. He works for Blu Arancio (www.bluarancio.com). He is a Microsoft Certified Solution Developer and a Microsoft Certified Application Developer for .NET, a Microsoft Certified Professional, and a prolific author and technical reviewer. Over the past ten years, he’s written articles for Italian and international magazines and coauthored more than ten books on a variety of computer topics.

Stephen Provine is a principal software design engineer on the Microsoft Visual Studio team. He has 14 years of experience working across many aspects of the Visual Studio rapid application development (RAD) experiences, including the Server Explorer, SQL database tooling and data designer extensibility, and was a key member of the Visual Studio LightSwitch team, contributing across all areas of the product. Stephen is currently a technical leader in the Azure Developer Experience group, working across the breadth of tooling that aids developers in being most effective when developing applications for Microsoft Cloud. Prior to working at Microsoft, Stephen received a bachelor’s degree in computer science from Harvard University.

xxv

Acknowledgments I’d like to thank everyone who supported me during the writing of this book. While I wrote this book, I was unable to spend much time on my other project work. I’d like to thank everyone for their patience with me during that time. James DeWolf at Apress played an important role in commissioning this project. I’d like to thank James and my editor, Melissa Maldonado, for their help throughout this process. I also want to thank Stephen Provine for all the assistance he gave me during this project. Finally, I’d like to thank the readers who purchased this and the previous editions of this book. Without those readers, this third edition would not have been commercially viable, especially for a niche product such as LightSwitch.

xxvii

Introduction When I look back at the time that I have spent with LightSwitch, the product almost feels like a child of mine. I started using LightSwitch during the beta version when the product was in its infancy. Through the years, I’ve seen LightSwitch grow to be the mature product that it is today. The early years were exciting. The concept was revolutionary, and there was a great buzz around the product. However, the documentation was poor, which inspired me to write the first edition of this book. I wanted to share my experience and to help developers avoid making the same mistakes that I made. As developers began using LightSwitch and as market conditions changed, the product adapted to meet the changing environment. As an example, the first version of LightSwitch employed RIA services as the communication channel between the client and server. In 2012, Microsoft rewrote this part of LightSwitch to use OData instead. Another significant feature that Microsoft added in 2012 was the HTML client. This enables you to build HTML5-compatible applications that are optimized for touchscreen and mobile devices. In subsequent releases, Microsoft improved several other areas of LightSwitch. A notable example is the improvements to the Visual Studio design environment. Early developers will remember how Visual Studio provided two views of a solution: a simplified logical view and a more advanced file view. In 2013, Microsoft replaced this with a simplified single view. Today, Visual Studio also provides much better IntelliSense and debugging support, particularly for JavaScript—an area for which support has previously been weak. Another significant addition was the Server Application Context. This feature makes it possible to execute data-access code on the server, outside the context of a LightSwitch application. All of this illustrates how LightSwitch has evolved into a far more powerful product. In recent times, Microsoft has not been as proactive in further developing LightSwitch. Some developers are concerned about this, but I see this as a sign of a mature product. LightSwitch does everything that Microsoft intended it to do, and there is little more they can profitably add. If you’re just starting out with LightSwitch, my view is that now is a great time to begin. You can be confident that you’re working with a stable and mature product that has been tested by thousands of developers. There are few competing products that can match the capabilities that LightSwitch offers. I’ve personally gained a lot from LightSwitch. With the help of LightSwitch, I’ve built some great applications with minimal time and effort. Through the work of this book, I’ve also had the chance to work with some really smart people in the Microsoft Visual Studio team. By reading this book, I hope that you can attain similar rewards and develop some great applications at the same time.

Who This Book Is For This book is designed for readers who want to build data-driven business applications quickly. You don’t need to have any prior knowledge of LightSwitch, but it helps if you know a little about .NET and database development in general.

xxix

■ Introduction

How This Book Is Organized If learning LightSwitch seems like an enormous task, don’t worry! You might have heard of the Pareto Principle, which also goes by the name of the 80/20 rule. This rule states that in most situations, 20% of something causes 80% of the results. If you apply the Pareto Principle to this book, it suggests that you can accomplish 80% of what you want to accomplish by reading less than four chapters. And, in fact, the first four chapters highlight the key topics that are all you need in order to build an application that’s almost 80% complete. By the end of Chapter 4, you’ll understand how to create data tables and attach to external data. You’ll know how to build applications that include Data Entry screens and navigation controls. The type of data entry screens I’ll describe will include screens that show lists of data and those that enable the entry and display of single records. You’ll also discover how to provide drop-down controls to enable users to make selections during data entry. In short, you’ll know how to build a working business application with enough functionality to perform most basic tasks. In the next part of the book, I’ll show you how to write code and queries. This includes .NET code that runs on the server and Silverlight desktop client, and JavaScript code that runs on HTML client applications. Unless you want to create an application that’s completely isolated from other systems, it’s useful to know how to attach to unusual data sources and how to share your LightSwitch data with other applications. You’ll discover how to do this through RIA services and OData. You can extend your Silverlight applications through custom controls and extensions, and you’ll find an entire section of the book devoted to this topic. The remaining chapters of the book show you how to build reports, integrate with email systems, and deploy your application.

The Sample Application Most of the chapters include code samples that refer to a Help Desk application. The purpose of this application is to relate the technical content in the book to a real-life scenario that you can more easily understand. The Help Desk application is typical of the applications that you can build with LightSwitch. Its features are simple enough to understand, yet complex enough to show off the more advanced features of LightSwitch. It is designed to help companies manage problems, and it’s especially suitable for departments that deal with technical support issues. It allows users to record the actions they carry out to resolve a problem while giving managers an overview of all current issues. Figure I-1 shows a screen from this application and illustrates some of the features that I’ll cover in this book.

xxx

■ Introduction

Figure I-1.  Typical screen from the Help Desk application Figure I-1 shows the Data Entry screen through which users can enter help-desk issues. They can set the user that the issue relates to and allocate an engineer to the record. The Data Entry screen allows users to respond to the issue, attach documents, register feedback, and record the amount of time that engineers spend on the task. To help you recreate this application, you can find a summary of the application’s tables in Appendix E.

xxxi

■ Introduction

Code Samples LightSwitch supports C#, VB.NET, and JavaScript. This book includes code samples in all three languages. To make life simple, LightSwitch hides much of the complexity that’s associated with application design. When you want to write some code, you do so by clicking on a Write Code button that LightSwitch shows in its graphical designers. This button shows a list of events that you can handle. When you select one of the options in the list, LightSwitch opens a Code Editor window that you can use to author your code. When you’re starting out with LightSwitch, it isn’t always obvious where your code is stored. To add some clarity, each code listing includes a file location, as shown in Listing I-1. Listing I-1.  “Hello, World!” example VB: File: HelpDeskVB.Server\DataSources\ApplicationData\_ApplicationDataService.lsml.vb Imports System.Text.RegularExpressions 'REM VB Code appears here Dim message = "Hello, World!"

 

C#: File: HelpDeskCS.Server\DataSources\ApplicationData\_ApplicationDataService.lsml.cs using System.Text.RegularExpressions; //REM C# Code appears here var message = "Hello, World!";

 

For both the VB and C# examples in Listing I-1, the File heading specifies the file name and path. In this example, HelpDeskVB and HelpDeskCS prefixes identify the name of your LightSwitch application. The Server part indicates that the code refers to the Server project. This piece of information is useful, because it informs you that the code runs on the server rather than on the client. (You’ll learn all about this in Chapter 1.) The next part of the file heading, DataSources\ApplicationData, indicates the folder in the Server project that contains the code file. Finally, _ApplicationDataService.vb and _ApplicationDataService.cs refer to the name of the VB or C# file that the listing shows. If a piece of code requires you to reference a .NET namespace, the code listing will show the necessary import (VB.NET) or using (C#) statements. Be sure to add these statements to the top of your code file. Many of the code samples include numeric symbols to help you locate specific lines in a code listing. For example, line  defines a comment, whereas line  declares a variable. There’s obviously no need to enter these numeric symbols when you recreate this code for real! As in all books, the length of a code line can exceed the width of the page. In most cases, I’ve put line breaks in places that still allow the code to compile, but in some circumstances this isn’t possible. Notable examples include namespace declarations in XAML files and VB.NET keywords like inherits and implements. If your application doesn’t compile, it’s worth checking your code for extraneous line breaks.

xxxii

■ Introduction

Tips/Notes/Cautions This book includes callouts with tips, notes, and cautions. Tips are helpful hints or pieces of information that may be particularly interesting. Notes provide you with nonessential—yet interesting—additional information about a particular topic. Cautions alert you to anything that might be detrimental to your work or could cause damage.

Comments and Errata Although my editors and I have tried to be as accurate as possible, mistakes do sometimes happen (particularly with a book of this length). If you have any feedback or want to report any bugs, please visit the official page for this book at the Apress website: http://www.apress.com/9781484207673 This page also shows any mistakes that we’ve found following the publication of this book. 

xxxiii

Part I

Introducing LightSwitch

Chapter 1

Introducing LightSwitch When I first began working in LightSwitch, I was mystified at how everything worked. Although you can build applications quickly, easily, and with minimal effort, this simplicity is possible only because LightSwitch abstracts away much of the internal workings and plumbing code. At first, this isn’t a problem, because there’s no need to understand what happens beneath the surface. But as your applications become more complex and sophisticated, application development makes more sense if you understand how both the underlying architecture and the build process work. Therefore, this chapter will provide an overview of the parts that make up an application, which it will do by describing the following key topics: •

The three-tier architecture that LightSwitch uses



How LightSwitch applications are based on XML models



How LightSwitch applications apply the MVVM pattern

By the end of this chapter, you’ll understand how LightSwitch applications are architected, and also recognize what happens when you build and compile an application.

What’s New in 2015 Let’s begin by taking a look at the history of LightSwitch. Back in 2010, Microsoft released the very first version of this tool. Microsoft designed LightSwitch as a rapid application-development tool for building Silverlight-based, data-driven line-of-business applications. Businesses could use LightSwitch to build applications for storing, viewing, and retrieving data. Example use cases might include applications for managing sales figures, assets, or customers. In fact, any application that requires a “forms-over-data” interface is an ideal candidate for LightSwitch. The fact that LightSwitch is Silverlight-based meant that Microsoft could market the product as a tool for building both desktop and web applications. As a first release, the product worked very well. It filled a niche in the market and liberated many developers. Of course, there were various things that didn’t work so well, but you’d expect this from a first release. In 2012, Microsoft updated LightSwitch as part of the Visual Studio 2012 release. This release included bug fixes, new data types, and controls. It also added localization support and replaced a dependency on SQL Server Express at design time with LocalDB. Prior to this, there were often occasions at debug time when the running application would fail to load data and would show a red X instead. The introduction of LocalDB did a lot to improve design-time reliability. As time progressed, the Silverlight nature of LightSwitch became more of an issue. The browser applications that LightSwitch generates require the user to install the Silverlight plugin, and this plugin isn’t available on all platforms or devices. Not only were Silverlight and third-party plugins falling out of favor, but also the use of Silverlight presented a practical problem in that LightSwitch applications wouldn’t work well on mobile devices, the Apple iPad being a prime example. To address these issues, Microsoft added the HTML client during a second update to Visual Studio 2012. This major new feature allowed developers to create native HTML5 applications that worked on all major web browsers. To support this change, Microsoft

3

Chapter 1 ■ Introducing LightSwitch

changed the method that the LightSwitch client used to communicate with the server. The underlying implementation changed from RIA Services to OData. Despite the fact that this was a major structural change, it would have been invisible to most developers and end users. Further changes to LightSwitch came in Visual Studio 2013. Microsoft added the ability to host your application as a SharePoint app. The benefit of this is that it enables LightSwitch applications to be integrated into SharePoint. This feature also better aligns LightSwitch with Microsoft’s cloud strategy. It means you can choose to host your application through Microsoft’s SharePoint 365 subscription service, and to leverage the Office 365 services as well. In Visual Studio, Microsoft added a Cloud Business Apps template. This makes it possible to use LightSwitch technology to build applications that are targeted for Azure. As a result of all the advancements since the first release, LightSwitch has reached maturity. Thus, the 2015 release contains fewer new features. Despite this, if you need a way to quickly build line-of-business applications, my view is that LightSwitch remains one of the best tools on the market.

Understanding LightSwitch’s Architecture A problem some organizations face is that often application development is carried out by individuals whose main job is not in IT. The stereotypical applications that such developers produce include enormous Excel spreadsheets with convoluted VBA (Visual Basic for Applications language), or poorly thought out Access databases. Although these developers are very smart in their own industries and business processes, they aren’t formally trained and don’t know how to properly structure an application. When the person leaves, the business can end up inheriting a mess of an application that’s very difficult to maintain. With LightSwitch, this problem is less likely to occur, because the application imposes an architecture that separates user interface, business logic, and data. When you create a new solution, LightSwitch creates separate projects that are built to execute on a specific tier in this architecture. LightSwitch makes it difficult for you to write code in the wrong place (for example, business-logic code in the user-interface layer), and this in turn leads to applications that are more maintainable and scalable. Figure 1-1 illustrates the parts that make up a LightSwitch application. It highlights the way that applications are separated into data, logic, and presentation tiers. It also illustrates how each tier communicates with the others.

Figure 1-1.  LightSwitch’s architecture

4

Chapter 1 ■ Introducing LightSwitch

The Data Tier The data tier describes the place that physically stores your data. With LightSwitch, you can read and write data that’s stored in SQL Server, SQL Azure, SharePoint, and many other data sources. These data sources make up the data tier. In fact, your data storage options are almost limitless. This is because you can connect to almost any data source by creating your own custom RIA service. A very special database that exists in all LightSwitch applications is the Intrinsic (or Application Data) database. LightSwitch inserts any table you add through the Visual Studio designer into this database. Another purpose of the Intrinsic database is to store user details. LightSwitch uses the ASP.NET SQL membership provider to manage users and roles. The database tables that are used by the membership provider are stored in the Intrinsic database. During design time, LightSwitch hosts the Intrinsic data using LocalDB (the successor to Microsoft SQL Server Express). But when you deploy your application, you can host the Intrinsic database using any version of SQL Server 2005 or above.

The Logic Tier The LightSwitch client application doesn’t communicate directly with the underlying database or data store. Instead, it performs data access by calling services in the logic tier. There are two places where you can host your logic tier. In the case of a Silverlight desktop application, you can configure the logic tier to run on the end user’s machine. But in the case of a web application, you need to host the logic tier on a web server. Technically, LightSwitch builds an ASP.NET application that you can deploy to an IIS Server, or to Azure. LightSwitch creates a data service for each data source in your application. Data services are responsible for reading and writing data to the data source, and they also perform any business logic that’s applicable (such as data validation). LightSwitch exposes the data service as an OData end point at the logic-tier boundary. When the LightSwitch UI carries out some data access, it does so by communicating with an OData end point that the data service exposes at the logic-tier boundary.

Data Retrieval Process Data services expose entity sets for each table in the corresponding data source. Entity sets are containers for items of the same record type, and all data access is carried out through an entity set. Entity sets expose operations that return data to the client. By default, these operations include queries that return all records in a table, or single records filtered by a primary-key value. Any queries that you create are also exposed as operations via the entity set. Figure 1-2 illustrates a typical data operation. When the LightSwitch UI requires data, it calls a query operation on the entity set. In this example, the query operation relates to a user-defined parameterized search query to find customers by surname. This query allows the client to pass in an argument that specifies the search criteria.

Figure 1-2.  Calling a query that returns customers filtered by surname

5

Chapter 1 ■ Introducing LightSwitch

When the data service executes the query, it passes through the Query pipeline. This opens up various phases where you can add your own custom code. During the pre-processing phase, for example, you can tailor the results of a query by adding extra filter conditions using LINQ (language-integrated query) code.

Data Saving Process Entity sets provide an operation called SaveChanges. As the name suggests, this method starts the process that saves any updated data. Let’s see how this save process works. At the very beginning (before SaveChanges is called), the client calls a query operation on an entity set that returns an initial set of data. The client caches the data that the query returns. When a user modifies data, the client generates an object called a change set. This object contains the deltas, and the application uses this to maintain a record of any records that the user adds, updates, or deletes. When the user clicks on the Save button, the LightSwitch client calls the SaveChanges operation and passes in the change set. Before the changes are committed to the database (or the underlying data store, such as SharePoint), the processing enters the Save pipeline. Just like the Query pipeline, the Save pipeline provides places where you can intercept the save operation by writing custom code. For example, you can prevent certain users from updating data by including code in the Save pipeline. We’ve already seen how LightSwitch applies best practices without you having to do much extra work, and the Save pipeline is yet another example of this. If LightSwitch detects conflicting changes that have been made by other users, it won’t allow the save operation to succeed. Instead, it shows what the current and proposed values are, and allows the user to choose what to do. LightSwitch also maintains the consistency of your data by applying all updates inside a transaction. For example, any proposed change to a parent record won’t be applied if an update to a child record fails. Without LightSwitch, you could spend ages writing this type of boring, repetitive, boilerplate code. This is yet another example of the timesaving that you can achieve with LightSwitch.

The Presentation Tier The presentation tier defines the part of LightSwitch that runs on the user’s computer or device. The tier actually performs a lot of work. It shows data to the user, allows data entry to happen, and controls all other tasks that relate to human interaction. Importantly, it also performs business logic such as data validation, keeps track of data changes, and interacts with the data services in the logic tier. You can build your user interface (or client) by using either Silverlight or HTML. In fact, the choice isn’t mutually exclusive. You can include both Silverlight and HTML clients in a single LightSwitch application.

HTML Client Microsoft introduced the HTML client in LightSwitch 2012. This client is highly recommended if you want your application to work on mobile or touchscreen devices. The advantage of using the HTML client is that your application can work on a wider range of devices. In comparison, a Silverlight application running in a browser requires the user to install the Silverlight runtime. This isn’t always possible, particularly on mobile devices or on locked-down corporate environments. You can customize HTML-client applications by using JavaScript and CSS (cascading style sheets). If you have experience writing web applications, you can very easily use your existing skills. For more traditional developers, coding in .NET code is usually easier than doing so in JavaScript. For these developers, the Silverlight option can offer better productivity.

6

Chapter 1 ■ Introducing LightSwitch

Silverlight Client The benefit of a Silverlight front end is that it provides a rich experience for both developers and end users. For example, you can carry out COM automation or automate Microsoft Word/Excel using Silverlight. This isn’t possible with an HTML client. It’s also easier to write client-side code when you’re using Silverlight. You can use strongly typed C#/VB code and carry out more tasks in code. For example, you can perform security operations or use LINQ syntax to query data on the client. You can set up your Silverlight client to run either out of browser as a desktop application or inside a browser as a web application. You can switch your application from one mode to the other by simply clicking a radio button in the properties of your LightSwitch project. LightSwitch web applications are hosted through the Silverlight runtime that the user installs in their browser. Your application executes inside a sandbox, and access to features such as Export to Excel is prohibited. Access to certain parts of the file system is also restricted. In the case of a desktop application, the hosting service is provided by the Silverlight out-of-browser host service (sllauncher.exe). In this scenario, your application is automatically configured to require elevated permissions, and therefore has access to features such as Export to Excel and COM-based automation.

LightSwitch Shell Shells are a feature of the Silverlight client. They control the location of all major UI elements and perform application level tasks. Examples of the tasks that a shell carries out includes handling the logging in process, building screen navigation menus, and composing the screens that application shows to the user. You can set the shell for each application through the properties pane of your project. The two default shells that ship with LightSwitch are called Standard and Cosmopolitan. (See Figure 1-3.)

Figure 1-3.  Standard and Cosmopolitan shells LightSwitch provides many extensibility choices, and if you don’t like these built-in shells, you can choose to write your own.

7

Chapter 1 ■ Introducing LightSwitch

Applying Themes to Your Application Themes are another feature of the Silverlight client. They contain a set of styles and help control the fonts and colors that your application uses. Unlike when changing the shell, themes apply presentational changes that are much more subtle. As with shells, you can use the properties pane in your project to set the theme for an application. Themes are often designed to work with a specified shell, but it’s entirely possible for you to mix and match the shells and themes. The way to manage the look and feel of an application is through shells and themes. New developers often struggle to set control attributes (such as fonts and colors) because many of these attributes are designed to be controlled by a theme, rather than set for each individual control. Once again, LightSwitch applies good practice by encouraging you to apply consistent style settings throughout your application. Themes are also one of several LightSwitch extension points, and I'll show you how to create your own later in the book.

Understanding LightSwitch Screens A screen represents a piece of user interface that users can utilize to view or enter data (just like a form in an Access application or a web form in an ASP.NET application). Developers create screens with prebuilt functions by using templates. For example, there are templates for creating search, data edit, and data entry screens. You can also create your own screen templates—this is another extensibility point that LightSwitch offers. Desktop applications feature a tabbed interface. Users can open multiple screens, and each screen opens in a separate tab. Each screen contains an object called a data workspace that is responsible for fetching and managing data. The data workspace manages the state of the data in the change set that is submitted to the data service on the logic tier when the user initiates a save. Because each screen contains its own data workspace, data changes that a user makes in one screen are not visible in other screens. You can’t share data changes between screens, because each screen maintains an independent view of the data. Unlike desktop client applications, HTML client applications feature a single document interface and can only show one screen at a time. All screens in an HTML client application share the same data workspace. If a user makes data changes on multiple screens, the application’s Save button will commit all of the data changes that have made during the session. When you write screen code, you need some way to reference objects such as data, controls, or screen parameters. These objects are exposed via an object called the screen object, which you’ll learn how to use in later chapters.

Introducing the Model-Centric Architecture LightSwitch’s model-centric architecture is a brilliant piece of software engineering. The model-centric architecture defines your LightSwitch application (data items, screens, queries) within XML files that are named with an LSML extension. When you run your LightSwitch application, the LightSwitch runtime processes the XML data and transforms it into a working application. As a very loose analogy, think of the LightSwitch runtime as a copy of Microsoft Word. Using this analogy, your LightSwitch application would be a Microsoft Word document. In the same way that Word opens Word documents and makes them readable and editable, the LightSwitch runtime opens LightSwitch applications and makes them functional. The advantage of this architecture is that LightSwitch isn’t strongly tied to any specific technology. If Microsoft wants LightSwitch to run on a different platform or device, it can be done by simply writing a new runtime. Following on from version 1 of LightSwitch, this is exactly what happened with the HTML client. As another example, Microsoft changed the communication protocol between the client and server from RIA Services to OData with the release of LightSwitch 2012.

8

Chapter 1 ■ Introducing LightSwitch

Building Your Application Figure 1-4 shows the parts that make up a LightSwitch application, from design time through to runtime. For desktop applications, a solution consists of three groups of .NET code: client, common, and server code. Server code runs on the server, client code runs on the client, and common code runs on both the client and the server. An example of common code is data validation. In most cases, the client validates data before sending it to the server. When the data reaches the server, the server revalidates the data using the same common code.

Figure 1-4.  LightSwitch build process Note that with the HTML client, the notion of shared common code doesn’t exist, because the server and client are based on different technologies. The server components are based on .NET, while the language that is used on the client is JavaScript. To further explain the build process, let’s start at the bottom of the diagram in Figure 1-4. As part of the model-centric architecture, LightSwitch applications are constructed from building blocks. Think of these as XML representations of the objects that you find in the LightSwitch designer. Let’s say that you add a data source to your application. When you do this, LightSwitch expresses your data source as an XML element inside an LSML file in your server project. When you finish in Visual Studio, your application will be defined entirely in XML, and this is known as the LSML Model. During the build process, LightSwitch auto-generates classes that support your application. This autogenerated code includes the data workspace classes and the screen object classes. When you build your application, LightSwitch compiles the .NET code in your application. This code includes the auto-generated code, in addition to any custom code that you write. The interesting thing about the LightSwitch client is that the solution doesn’t include any files that contain UI definitions in XAML (Extensible Application Markup Language) or HTML. Instead, the LightSwitch runtime dynamically generates the screens and UI at runtime. In the case of the Silverlight client, the dynamic generation of screens, controls, and the shell takes place using MEF (the Managed Extensibility Framework) and data templates.

9

Chapter 1 ■ Introducing LightSwitch

This dynamic generation prohibits developers from directly modifying the XAML or HTML that the application produces. More experienced developers who prefer to hand-craft the raw UI can find this behavior limiting. However, LightSwitch does provide some flexibility for building custom UI elements in XAML or HTML through custom controls and methods in the HTML client.

■■Note  You can create LightSwitch projects in C# or VB.NET. However, you can't change a project from one language to the other after it has been created.

Understanding MVVM (Model-View-ViewModel) LightSwitch applications follow a design pattern called M-V-VM (also known simply as MVVM). This pattern was developed by John Gossman (a technical architect at Microsoft) and is commonly used by Silverlight developers. MVVM keeps the presentation, logic, and data elements of your application logically distinct. This pattern helps you develop applications that are cleaner, more maintainable, and more testable. The Model part of MVVM refers to the conceptual representation of the data. The entities and queries that you define in your application make up the model. At runtime, LightSwitch constructs a screen layout by interpreting the LSML model. The screen layout consists of a tree of content items, which could represent data items, lists, commands, or items that control the layout of your screen. A content item at runtime represents the View Model element of MVVM. The view model controls the client-side business logic (e.g., validation) and also manages data access. Next, the LightSwitch runtime builds a visual tree that contains the controls that it shows on screen. The Silverlight or HTML controls make up the View part of MVVM. Views are designed only to display data— nothing more. Because views are designed only to display data, you can easily change the control that’s bound to a data item (Figure 1-5). This is one of the biggest benefits that the MVVM pattern offers you.

Figure 1-5.  Changing the views that are bound to a data item

Walkthrough: Creating a LightSwitch Project So far, we’ve covered a lot of theory. To round off this chapter, I’ll move on to something practical and show you how to create a new project. This section will help you familiarize yourself with the Visual Studio designer, and also help you understand the layout of a LightSwitch solution. Start by opening Visual Studio and choosing the File ➤ New Project option. In the list of templates, you’ll find the option to create either a Desktop or HTML Application (Figure 1-6).

10

Chapter 1 ■ Introducing LightSwitch

Figure 1-6.  Creating a new project Choose “LightSwitch HTML Application,” enter a name for your project, and click the OK button. Once you do this, you’ll see the view that’s presented in Figure 1-7. Note that if you don’t see the LightSwitch templates, re-run Visual Studio setup and check that you’ve selected the LightSwitch option.

Figure 1-7.  What you see when you first create a project Notice that the view in Solution Explorer contains three nodes: a node that represents your application, an HTML client project, and a server project. As the names suggest, the server project contains the code and objects that run on the server, whereas the HTML client project includes the HTML/CSS/JavaScript code that runs on the browser. If you choose to create a desktop application, you’ll see a desktop client project, rather than a HTML client project. The initial start screen helps you get started by providing quick links to either create a table or to attach an external data source to your application. In the next chapter, I’ll show you how to set up your data. You can access a variety of menu functions through the right-click and context menu items for these three nodes. Here’s an overview of what you can do through these items in Solution Explorer:

11

Chapter 1 ■ Introducing LightSwitch



Application: This enables you to configure general, extension, and access control properties. You can use the right-click menu option here to add additional clients.



Server: The server project enables you to manage tables, data structures, and queries.



Client: The client project enables you to create screens, edit the menu items in your application, and write code that runs on the client.

Setting Application Properties Through the properties of the application node, you can configure general properties that relate to your application as a whole, as shown in Figure 1-8.

Figure 1-8.  Application properties An important menu option that you can access through the right-click context menu of the application node is the option to add additional clients. Although we initially created a HTML application, LightSwitch solutions can include both HTML and desktop clients. An application with both clients might contain a fully rich desktop client that’s designed for office workers, with a scaled-back HTML client that contains a read-only, or subset of features, and is designed for mobile workers. Of course, the advantage of a solution with two clients is that both client applications can share the same server-side objects, such as code, queries, and validation. To add an additional client, right click the application node and choose the “Add Client” option to open the dialog that’s shown in Figure 1-9. Click the OK button to add the additional client to your project.

Figure 1-9.  Adding additional clients

12

Chapter 1 ■ Introducing LightSwitch

During development, you can debug and run your application by clicking the F5 button, or by using the green Play button on the Visual Studio toolbar. In a solution that contains both HTML and desktop clients, you can select the client you wish to debug by selecting the right-click “Set as startup” menu option. LightSwitch gives you the ability to host your HTML client applications in SharePoint. An important point to bear in mind is that once you add a desktop client to your solution, you can’t later deploy your project to SharePoint. So, if you want to deploy an HTML application to SharePoint, make sure not to add a desktop client to your solution! Now that you've seen how to create a LightSwitch project, Chapter 2 will show you how to create tables and how to attach your application to existing data. Once you set up your data, I’ll show you how to build HTML and desktop client applications in Chapters 3 and 4.

Summary LightSwitch is a perfect tool for quickly building data-centric desktop or browser applications. Examples of applications that are ideal for LightSwitch include internal auditing, asset control, or customer database systems. The applications you build with LightSwitch are robust, because LightSwitch follows well-known patterns and best practices, such as three-tier application layering and MVVM. Applications consist of data, business logic, and client layers. For the client layer, you can build LightSwitch “front ends” using either Silverlight or HTML. A Silverlight application provides a richer experience, and can run as a desktop application. Desktop applications can interact with other desktop applications such as Outlook and Word, unlike a browser application. HTML applications are generally less powerful than their Silverlight counterparts, but benefit from being compatible with a far wider range of platforms and devices. With LightSwitch, you can read and write data belonging to SQL Server, SQL Azure, SharePoint, and many other data sources. All LightSwitch applications rely on a special database called the Intrinsic database. This database stores the tables that you create within LightSwitch, as well as the login details for your users. The LightSwitch client applications don’t talk directly with your database or data source. Instead, they access data by communicating with the logic layer. At the logic-tier boundary, LightSwitch creates a data service for each data source in your application. The LightSwitch client uses the OData protocol to communicate with the data service and to carry out data retrieval and update operations. Data access in LightSwitch revolves around the concept of a data workspace. Think of this as an object that provides access to the data sources, queries, and tables in your application. Each data workspace maintains a change set. A change set keeps track of data changes, and LightSwitch uses this to stop users from accidentally overwriting changes that other users have made. Desktop applications feature a tabbed interface, with each screen appearing in a separate tab. Each screen maintains its own data workspace. This means that each screen maintains an independent view of the data. Therefore, any data changes that a user makes on one screen won’t be visible on other screens. HTML applications, on the other hand, feature a single document interface. All screens in a HTML client application share a single data workspace. If a user makes data changes on multiple screens, the application's Save button will commit all of the data changes that have been made during the session. Having said this, the typical layout of an HTML client application usually prevents users from committing changes that they don’t currently see on the screen. When the server fetches or saves data for the client, code execution passes through the Query or Save pipelines. These pipelines expose points where you can write custom .NET code. For instance, you could write auditing code, or code that customizes the output of a query.

13

Chapter 1 ■ Introducing LightSwitch

For Silverlight applications, shell and theme settings enable you to reclothe or “skin” your application. Changing the shell allows you to radically change the appearance of your application, whereas changing the theme produces more subtle changes, such as with font colors and sizes LightSwitch applications are defined using XML building blocks, and the XML content is persisted in files with an LSML extension. LightSwitch auto-generates the client UI at runtime by interpreting the XML model. Therefore, your Visual Studio project won’t contain screen definitions in XAML or HTML that you can hand edit. LightSwitch uses the MVVM pattern. A big advantage of this pattern is that it keeps your project logically distinct and allows you to easily change the controls that are bound to data items.

14

Chapter 2

Setting Up Your Data The primary purpose of LightSwitch applications is to connect to and work with data. So, to get the most out of the product, it’s vital to understand the intricacies of working with data sources, tables, and fields. In this chapter, I’ll show you how to •

design tables and attach to existing data;



define relationships between tables; and



create computed properties and apply business types.

This chapter will describe the start of an application to manage help-desk issues. The intention is to provide an example of a business application that contains sufficient complexity to demonstrate the most prominent features of LightSwitch. In this chapter, you’ll learn how to create tables to store help-desk issues and engineer details. You’ll find out how to associate engineers with multiple issues and how to define a manager/engineer hierarchy by creating a self-referencing relationship. Later on, I’ll show you a technique to summarize data for each row in a table. This “summary property” combines each engineer's first and last name and provides a helpful way for users to identify records, particularly in lists of data.

Choosing Where to Store Your Data There are two approaches in LightSwitch that you can use to store data. You can create your own tables in the Intrinsic database by using the built-in table designer, or you can attach to an external data source. Of course, these two approaches are not mutually exclusive. You can create your own tables and also attach as many external data sources as you want in a single application. When you build tables using the built-in table designer, LightSwitch persists any data that you add at design time. So, if you add some data to a table during a debug session, your data will still be there during the next debug session. For this to work, LightSwitch creates a LocalDB development database in the location \Bin\Data\ \ApplicationDatabase.mdf. The benefit of creating tables in the Intrinsic database is that it makes your project self-contained. If you share your LightSwitch project with other users, they’ll be able to run your project without having to reattach the external data. The difficulty arises when you deploy your application. The deployment wizard doesn’t allow you to deploy your development data into the live environment. This can be frustrating if you’ve spent a lot of time entering data during the design process. So, if design time data is important to you, consider building your tables externally in a SQL Server database rather than building it internally within LightSwitch. The alternative is to create and execute data scripts on your deployment database after you install your application.

15

Chapter 2 ■ Setting Up Your Data

What Are Entities and Properties? Database developers often use the terms tables, rows, and columns. However, LightSwitch regularly refers to entity sets, entities, and properties instead. An entity represents the data from a single row in a database table, whereas a property is analogous to a field or column from a database table. LightSwitch uses Microsoft’s Entity Framework internally to provide object relational mapping. Entity and properties are terms that the Entity Framework uses, and are more appropriate given that LightSwitch can connect to non-relational data sources. For example if you connect to a SharePoint data source, list items map to LightSwitch entities, and list columns are exposed as LightSwitch properties. In this book, I use the words tables and fields interchangeably, because it’s often clearer to use the database terms. For example, a property in the screen designer can mean a local instance of an entity or something you can find in Visual Studio’s property sheet. And when you start talking about the properties of a property, things can quickly become quite confusing.

Creating Tables (Entities) Let’s start by creating a new table and defining some fields. We’ll create a table called Engineers that stores engineer details. From Solution Explorer, right-click the Data Sources folder and choose the “Add Table” option. At the bottom of the table designer, you’ll see a banner you can use to change perspective (Figure 2-1). These three views show the fields and settings you can access while you work in the server, HTML, or desktop client (Silverlight) projects in your solution. This feature is useful, because some of the properties in the server project aren’t available in the HTML client project.

Figure 2-1.  Creating a table and editing its properties

16

Chapter 2 ■ Setting Up Your Data

To configure the properties of a table, click the blue table-name heading and open the properties sheet. Here, you’ll find the table properties you can set (Figure 2-2). Some of the property values are specific to the perspective that you choose. For instance, you can apply different summary property and display name values for desktop and HTML clients (Figure 2-2).

Figure 2-2.  The table properties you can set will differ depending on the perspective The table properties you can set include: •

Name – The name value uniquely identifies your table. The name must begin with an alphabetic character and can only contain alphanumeric characters and the underscore character. Other special characters such as spaces or the full stop character are not permitted. The table name has a maximum length of 64 characters.



Display Name – This is the friendly name that describes your table; it can contain spaces.



Description – The description field provides a long description of the table.



Plural Name – LightSwitch uses the value you enter here to name the collections of entities you add to a screen. You also use the plural name to refer to collections of entities when you write code. The maximum plural name value you can set is 64 characters.



Summary Property – Think of this as the “display” field for a table. The summary property specifies the property that identifies a data row to a user. You can add a control to your screen called a summary control that displays the value of this property to the user.



Default Screen – The summary control renders itself as a link. When a user clicks this link, it opens the default screen that you specify here. In desktop client perspective, there is an option to select “Auto” from the drop-down list. If you select this, LightSwitch displays an auto-generated screen. In HTML applications, the concept of an auto-generated screen doesn’t exist.

17

Chapter 2 ■ Setting Up Your Data



Is Searchable – Selecting this ensures that the text properties in the table will be searchable.



Enable Created/Modified Properties – When you select this option, LightSwitch automatically stores the username and date/time on which each record in the table was created and modified. You can use this feature to implement row-level tracking.

■■Tip  If you want to secure your application so that users can only work with the records that they created, make sure to check the “Enable Created/Modified” property.

Creating Fields (Properties) Once you add a table, you can define the data you want to store by creating properties (or fields). To do this, switch to the server perspective and use the table designer to define your properties. For each field you add to a table, you need to specify the type of data that the field will store. Let’s take a look at some of the data types that you can use.

■■Caution  Try not to name your fields using words that are reserved keywords in SQL Server or the Entity Framework. Prefixing field names with the word Entity (e.g., EntityKey) caused unexpected errors in LightSwitch 2011. This particular bug has now been fixed.

Storing Textual Data In a typical application, much of the data you store will be string (or textual) data. The string data type includes support for international character types (e.g., Arabic, Chinese, and Japanese). For best performance, it’s a good idea to set the maximum field size to a value that’s no longer than the maximum length of the data that you want to store. If you want to store unlimited-length/multi-line text, clear the contents of the maximum field textbox and leave it blank, as shown in Figure 2-3.

Figure 2-3.  Setting a string field to store text with unlimited length

18

Chapter 2 ■ Setting Up Your Data

Storing Numbers (Double and Decimal Types) If you want to store numbers with decimal places, you can choose to use either the double or the decimal data types. The practical difference between these two types is that doubles can store a wide range of numbers in a smaller amount of memory. However, doubles are less precise and are subject to rounding errors when you perform calculations against them. Decimals do not suffer from such rounding errors but do take up more space and are slower to compute. Sums of money should always be based upon the decimal data type. Other important attributes that relate to decimals are precision and scale. Precision defines the total number of digits in a number. Scale defines the number of digits after the decimal place. Figure 2-4 illustrates precision and scale using the example number 123456.789.

Figure 2-4.  Precision and scale Decimal fields in LightSwitch are created with a default precision and scale of 18 and 2, respectively. In keeping with good practice, you should shorten these values if that level of accuracy is too precise for your needs.

Storing Numbers (Integer Types) If you want to store numbers without decimal places, there are three data types you can use: short integer, integer, and long integer. The range of data values that you want to store dictates the data type that you choose. The maximum positive or negative values you can store for each of these data types are approximately as follows: short integer, 32 thousand; integer, 2 billion; long integer, 9 quintillion (that’s a 9 with 18 zeroes after it).

Formatting Numeric Fields You can specify a display format for each numeric property that you define in LightSwitch. When LightSwitch shows the data on a user’s screen, it formats the value using the pattern you supply (for desktop applications only). Figure 2-5 shows a field that stores a feedback rating. A format string of N2 means that LightSwitch formats the number to two decimal places.

19

Chapter 2 ■ Setting Up Your Data

Figure 2-5.  Setting the format .NET format strings begin with the format specifier, followed by a number that indicates the desired number of decimal places. Table 2-1 shows the format specifiers that you can use. Table 2-1.  .NET Format Specifiers

Format Specifier

Description

C or c

Currency

D or d

Decimal

E or e

Scientific (exponential)

F or f

Fixed-point

G or g

General

N or n

Number

P or p

Percentage

R or r

Round-trip

X or x

Hexadecimal

■■Note  The initial version of LightSwitch didn't include the feature to format numeric fields with .NET format strings. In 2011, I submitted this idea on Microsoft Connect, a website you can use to provide feedback on how to improve Microsoft products. I'm pleased that Microsoft chose to add this feature to LightSwitch, and it's reassuring to know that they do listen to customer feedback. https://connect.microsoft.com/VisualStudio/feedback/details/654220/lightswitch-allow-datato-beformatted

20

Chapter 2 ■ Setting Up Your Data

Storing Images The image type provides storage for image data. For desktop applications, LightSwitch includes image editor and image viewer controls with which users can upload and view images. Note that these controls only support images in JPG and PNG formats. If you want to upload and view image files in other formats, you need to write or purchase a third-party custom control.

Storing Binary Data You can use the binary data type to store binary large objects such as documents, videos, or other file types. Chapter 11 will show how you can write the screen code to enable users to upload and download files in your application.

Storing Dates There are three data types that you can use to store dates: date, datetime and datetime offset. The date data type stores dates without a time component, whereas datetime is designed to store simple dates and times. Datetime offset is the best of all these data types, because it stores the time zone value, and stores a wider range of date values to a greater level of accuracy. Here’s an example of where you would use the datetime offset data type. Imagine an order-processing system for a company that’s hosted on a US server. When the company dispatches an order, the warehouse operator sets the shipping time based on the local US time zone. If a customer from Europe chooses to view this order through a web interface, the shipping time should show the local European time, rather than US time. The datetime offset data type provides support for this scenario because it stores the time zone data. Other common applications that use the datetime offset data type are scientific or genealogy systems (for tracing family trees). The lowest date value you can store in a datetime field is 1st January 1973, whereas with datetime offset, the earliest value you can store is 1st January 0001. Another benefit of datetime offset is that you can store times to an accuracy of 100 nanoseconds (that’s one ten-millionth of a second). In comparison, datetime is less accurate and stores times by rounding up in increments of .000, .003, or .007 seconds. In the properties sheet for a date type field, you’ll find validation controls you can use to specify the minimum and maximum values in short date format (Figure 2-6). What might not be clear is the exact format in which you should enter these date values. The answer is that you should enter these values using the short date format that matches the regional settings of the computer that you’re developing on, rather than the regional settings of the server that you plan to deploy your application onto. For example, if you use a computer with British regional settings (like me) and want to restrict users from entering dates earlier than 1st April 2015, you would enter 01/04/2015, rather than 04/01/2015.

21

Chapter 2 ■ Setting Up Your Data

Figure 2-6.  Configuring date validation settings

Ensuring Unique Values The properties sheet for each field contains a checkbox called “Include in Unique Index.” Selecting this checkbox adds the field to a composite (or multi-column) index. It’s not possible to create individual unique fields through the designer. If you want to do this, you can write validation to enforce uniqueness at a field level. Chapter 5 contains sample code that will show you how to do this. Alternatively, you can create unique indexes on your SQL Server table if you’re using an attached SQL database.

Changing Data Types If you make major changes to the schema of a table in the Intrinsic database, LightSwitch may discard the data in your development database. At worst, it can even destroy and recreate your entire development database. However, it generally warns you before any data loss occurs (Figure 2-7).

Figure 2-7.  Warnings that appear before data loss occurs

22

Chapter 2 ■ Setting Up Your Data

Using LightSwitch Business Types LightSwitch includes special data types that you won’t find in other database management systems. These include Email, Money, Phone Number, Web Address, Percent, and People. These data types are called business types. They’re designed to store specialized data, and provide built-in validation and data-entry controls. These business types include properties that control how LightSwitch displays data on screen, as well as data-entry and validation characteristics. Let’s take a closer look at some of these business types.

Storing Email Addresses As its name suggests, the Email business type provides storage for email addresses. When you add an email field, there are two properties in the server perspective that you can set (Figure 2-8). •

Default Email Domain – If the user leaves out the email domain, LightSwitch appends the default email domain to the end of the email address. This setting is ideal for internal systems that are used by a single company.



Require Email Domain – When checked, the user must enter an email domain when entering an email address.

Figure 2-8.  Email business type properties

Storing Monetary Values When you add a money field to a table, you’ll find additional properties that you can set in client perspective (Figure 2-9). Any money-type controls you add to a desktop application will apply these settings at runtime. The specific settings you can set are: •

Currency Code – Use this field to specify the locale for the currency. For example, if you want to specify United States dollars, specify en-US. Appendix A shows a list of valid codes that you can use.



Is Formatted – If you select this option, LightSwitch applies formatting when you use the currency control on a desktop client screen to display your money value. The formatting that the control applies includes the currency symbol, the grouping separator, and decimal places.

23

Chapter 2 ■ Setting Up Your Data

Figure 2-9.  Money-field properties The options below only apply if you check the “Is Formatted” checkbox. •

Is Grouped – If checked, LightSwitch shows digit-grouping separators. For example, it displays 1,234,567.89, rather than 1234567.89.



Symbol Mode – You can choose from Currency Symbol, ISO Currency Symbol, or No Currency Symbol. Here are some examples of how LightSwitch formats a monetary value using the available symbol modes:





Currency Symbol - $123.45



ISO Currency Symbol - 123.45 USD



No Currency Symbol – 123.45

Decimal Places – This defines the number of decimal places LightSwitch shows when it formats a monetary value.

Note that although the HTML client includes money viewer and money editor controls, you cannot apply formatting settings at the table level, unlike with Silverlight clients.

24

Chapter 2 ■ Setting Up Your Data

Storing Phone Numbers The Phone Number business type validates data by making sure that users can only enter phone numbers that match a list of predefined formats. You can define formats by using the dialog that’s shown in Figure 2-10. The symbols you can use to define a format are: •

C – Country code



A – Area or city code



N – Local number

Figure 2-10.  Phone number format dialog Other additional symbols that you can use include: +, -, (,), . When a user enters a phone number through the desktop client phone number control, the control attempts to validate the phone number against the first format in the list. If the digits match the format, the phone number passes validation. Otherwise, the control attempts to validate the phone number against all remaining formats in the list until it finds a match. If a match isn’t found, LightSwitch prevents the user from saving the record.

25

Chapter 2 ■ Setting Up Your Data

When LightSwitch saves the phone number in the database, it saves the number without any formatting. If you want to create reports or use the phone number data outside of LightSwitch, you would need to write your own procedure to format the data. Unfortunately, it isn’t possible to specify additional formats on a global or application basis. If you want to do this, you must specify the additional format individually for each phone number field in every table.

Storing Web Addresses and Percentage Values The Web Address business type is designed to store web addresses. In desktop client applications, users can use the web address editor and web address viewer controls to add and view data. The Percent business type stores percentage values, and, just like for the other business types, LightSwitch provides percent editor and percent viewer controls for data entry.

Storing People Data The People business type stores usernames, or data that uniquely identify an individual. You might be interested in what benefit the People type offers. After all, you could simply store these values in a string field. The real benefit of the People type becomes apparent when you write code. The People type allows you to look up additional properties that are stored in Active Directory or SharePoint. For example, if you add a Manager field to the engineer table, the manager property includes helper methods you can call to look up the full name from Active Directory. Another benefit of this data type is that when you write queries, LightSwitch provides the ability to filter the contents of a People field by the current user. You can use this feature to show only the records that the logged-in user created.

Examining What Happens in SQL Server When you create a table in the table designer, LightSwitch creates the actual table in the Intrinsic SQL Server database. If you create a string property of 255 characters, LightSwitch creates a 255-length nvarchar column (a data type that stores variable-length Unicode data) in the underlying SQL Server table. You can access any property that’s visible in the table designer through code. When you write code, LightSwitch exposes table properties using .NET data types. Table 2-2 shows the mapping between LightSwitch, .NET, and SQL Server data types. Table 2-2.  Mappings between LightSwitch, .NET, and SQL Data Types

LightSwitch Type

VB.Net Type

C# Type

SQL Type

Binary Boolean

Byte()

byte[]

varbinary(max)

Boolean

Bool

Bit

Date

DateTime

DateTime

Datetime

DateTime

DateTime

DateTime

Datetime

DateTime Offset

DateTime

DateTime

Datetimeoffset

Decimal

Decimal

Decimal

Decimal

Double

Double

Double

Float (Continued)

26

Chapter 2 ■ Setting Up Your Data

Table 2-2. (continued)

LightSwitch Type

VB.Net Type

C# Type

SQL Type

Email Address

String

String

Nvarchar

Image

Byte()

byte()

varbinary(max)

Short Integer

Short

Short

Smallint

Integer

Integer

int

Int

Long Integer

Long

long

Bigint

Money

Decimal

Decimal

decimal(18,2)

Phone Number

String

String

Nvarchar

Percent

Decimal

Decimal

decimal(18,2)

Person

String

String

Nvarchar

String

String

String

Nvarchar

Web Address

String

String

Nvarchar

In Table 2-2, notice the business type mappings. LightSwitch uses SQL nvarchar and numeric types as the underlying storage type for business types.

Creating Choice Lists With LightSwitch, users can enter data by choosing an item from a “picker”-type control. In desktop applications, this control would be an auto-complete box, whereas in HTML client applications the control would be a drop-down box. In both cases, a choice list can provide the data source for the picker control. You define choice lists against table properties, and it’s possible to specify choice items on fields from external data sources, as well as on tables that you create yourself in the Intrinsic database. A choice list contains a set of name-value pairs, and you can configure these for most data types, including Boolean and numeric types. For example, you can create a choice list for a Boolean field with the choice values of Yes and No, or True and False. The data types that don’t support choice lists include image and binary types. To create a choice list, click on the Choice List link from the properties sheet for your field and enter a list of value and display name pairs. When the choices appear on screen at runtime, they will appear in the order that’s shown in the list. You can reorder the choices by right-clicking the item and selecting the “Move Up” or “Move Down” options, as illustrated in Figure 2-11.

27

Chapter 2 ■ Setting Up Your Data

Figure 2-11.  Reorder items using the right click context menu Unlike earlier versions of LightSwitch, the choice list dialog fully supports copy and paste. If you have data in an Excel spreadsheet, you can copy and paste your values across. This makes it easier for you to duplicate choice list data across multiple properties.

Choice List Versus Related Tables If you want your users to enter data by choosing from a list of available choices, you can either use a choice list or a related table. A choice list is ideal for data items that are relatively static. The disadvantage of using a choice list is that adding or deleting items requires you to recompile and redeploy your application, which can be cumbersome. Table 2-3 summarizes the pros and cons of choice lists and related tables. Table 2-3.  Choice List and Related Table Pros and Cons

Choice List

Related Table

Very simple to create

More complex setup. The choice tables need to be created and relationships set up.

Choice list values are deployed with your application.

An extra step is needed to populate the database table with values.

Adding or deleting requires a rebuild and redeployment of the application.

List items can be maintained through the application.

Choice list items must be duplicated if you want to use them in more than one field.

List items can be entered once into a table and used in multiple fields.

Defining Relationships If relationships exist between sets of tables in your application, it’s important that you properly define these in the table designer. Otherwise, screen design becomes very difficult, particularly when you want to use parent-child grids or drop-down (auto-complete) boxes. The following section will describe the various types of relationships you can define.

28

Chapter 2 ■ Setting Up Your Data

Defining One-to-Many-Type Relationships One-to-many relationships are a common type of relationship between two tables. The following example shows you how to set up your tables so that engineers can be assigned to multiple help-desk issues. To begin, create the Issue and Engineer tables as shown in Figure 2-12. At this point, no relationship exists between these two tables.

Figure 2-12.  Issue and Engineer tables without relationships To create the relationship, click the Relationships button in the designer toolbar and set up the relationship as shown in Figure 2-13.

Figure 2-13.  Relationship dialog

29

Chapter 2 ■ Setting Up Your Data

In the Relationship dialog, the Multiplicity row defines the type of relationship between the two tables— in this case, a one-to-many relationship exists between our two tables. This means that when a help-desk operator creates an issue, the operator must assign an engineer. The last row of the dialog defines the navigation property names for each table. This is where you can give a meaningful name to the relationship. In this case, the navigation property on the Issue table is named AssignedTo. If you want to add another relationship to the Engineer table (e.g., to store the name of the engineer that closes the issue), you can rename the navigation property to ClosedBy so as to clearly distinguish it from the other relationships that might exist between the two tables. The default navigation property name in this example would be Engineers1, which isn’t very meaningful. The purpose of a navigation property is to give you a way to navigate related entities. When you write code, these properties appear as objects you can use to reference child and parent entities. You can also query navigation properties by constructing language-integrated query (LINQ) expressions in code.

How Relationships Are Defined in SQL Server With LightSwitch, you define the relationships between tables through dialogs that use simple language. Although this simplifies the process for the novice, it might feel alien for more experienced database developers. If this applies to you, what follows is what happens when you create a relationship in LightSwitch (Figure 2-14).

Figure 2-14.  What you see in LightSwitch versus what you see in SQL Server Management Studio Figure 2-14 compares what you see in the LightSwitch designer to what you’d see in SQL Server. This diagram illustrates a modified version of the Issue table, which has been amended to store the engineer who closes the issue. This relationship is defined as a (zero-or-one)-to-many relationship, and the navigation property is called ClosedByEngineer. A (zero-or-one)-to-many relationship means that for an issue, setting a “closed by engineer” is optional. For the AssignedTo relationship, notice how LightSwitch creates a column in the issue table called Issue_Engineer. And for ClosedByEngineer, it creates a nullable column called Engineer_Issue. This allows SQL Server to support the (zero-or-one)-to-many relationship that we define. For both these columns, LightSwitch also creates a SQL Server foreign-key relationship to the Id column in the Engineer table. So, when you create relationships in the table designer, LightSwitch carries out the same keying that you would need to carry out if you were to create the tables manually.

30

Chapter 2 ■ Setting Up Your Data

Defining Self-Referencing Relationships Self-referencing or recursive relationships are relationships where entities reference themselves. You often find these when you model hierarchies. To illustrate this type of relationship, let’s modify the Engineer table so that it stores the name of the engineer’s manager. To create a self-join, open the relationship dialog and select the same table name in the To side of the relationship, as shown in Figure 2-15. Rename the navigation properties to Subordinates (in the From column) and Manager (in the To column). This creates two navigation properties for the engineer entity, each representing one end of the relationship.

Figure 2-15.  Setting up a self-join in the relationship dialog

Defining Many-to-Many Relationships In the relationship designer, many-to-many relationship types are not natively supported. If you want to create a many-to-many relationship, you need to create an intermediary table that contains two one-tomany relationships. To demonstrate this, here’s how to create a set of tables to store engineer skills. An engineer can have many skills, and a skill can be assigned to one or more engineers. Once you create the Engineer and Skill tables, create an EngineerSkill table to store the many-tomany relationship. In the table designer for the EngineerSkill table, create a one-to-many relationship between the Engineer and EngineerSkill tables. Next, create a one-to-many relationship between the Skill and EngineerSkill table. Figure 2-16 illustrates this table structure.

31

Chapter 2 ■ Setting Up Your Data

Figure 2-16.  The data structure behind a many-to-many relationship This completes the table design, and you’ll find out later in this book how you can create screens to enter many-to-many data.

Determining How Child Records Are Deleted When you create a relationship, you can use the On Delete Behavior setting to determine what happens when a user deletes a record. There are three possible options: •

Cascade delete



Restricted



Disassociate

In the engineer and issue example, setting the deletion behavior to cascade delete will delete all related issue records when a user deletes an engineer. If you set the behavior to restricted, engineers can’t be deleted until all related issues have been deleted. The disassociate option sets all engineer references to null on related issues prior to the deletion of an engineer. The disassociate option is only valid on (zero-or-one)-to-many relationships. The deletion behavior option is not available and is grayed out if you attempt to create a relationship between two separate data sources. Furthermore, these deletion options are only available for tables that belong in the Intrinsic database. They aren’t available for external data sources.

Attaching Existing Data The other way to use data in LightSwitch is to connect to an external data source. With LightSwitch, you can connect a wide range of data sources. When you choose the option to attach to existing data, LightSwitch provides five choices (Figure 2-17). You can attach to a database, a SharePoint list, an OData Service, an SAP, or a WCF RIA Service (Windows Communication Foundation Rich Internet Application Service).

32

Chapter 2 ■ Setting Up Your Data

Figure 2-17.  Attaching to an external data source The list doesn’t end there, however. As long as there’s an entity framework provider for your data source, LightSwitch can consume the data. This enables you to connect to data sources such as Oracle, MySQL, and other database management systems (as shown in Figure 2-18).

Figure 2-18.  Connecting to other database data sources If there isn’t an entity framework provider for your data, you can write your own RIA Service, OData Service, or even your own custom data source extension. These options enable you to connect to data sources that are not natively supported by LightSwitch.

33

Chapter 2 ■ Setting Up Your Data

When you attach to an external data source, you can’t add new tables or new fields. You also can’t rename existing fields or modify the schema of any of the attached database objects. However, you can change the data type of an attached field so that it uses a LightSwitch business type. For example, you can configure a SQL Server nvarchar field to use the Phone Number business type, rather than a string data type.

■■Tip  If you attach a table that contains an image column, LightSwitch sets the data type for that column to binary. If you want the column to behave as an image column and to use the built-in LightSwitch image controls, be sure to open the table in the designer and change the data type from binary to image.

Attaching to an Existing Database To attach to an existing SQL Server database, right-click the Data node in Solution Explorer and select “Add a Datasource.” Select the “Database” option and follow the steps in the wizard. You’ll eventually reach the dialog that’s shown in Figure 2-19, which prompts you to choose the tables and views that you want use in your LightSwitch application.

Figure 2-19.  Choose your database objects dialog LightSwitch doesn’t natively support stored procedures or user-defined functions, and these objects will not appear in the dialog that’s shown. If you want to use stored procedures, you can do so by writing a custom RIA Service.

34

Chapter 2 ■ Setting Up Your Data

■■Note  After attaching to an external table, you can use the table designer to reorder the columns. Although this will not affect the underlying SQL table, the data controls that appear on any new screens will be ordered in the sequence that matches the order that’s shown in the table designer.

Dealing with Missing Tables If a table does not include a primary key, LightSwitch will attempt to infer a primary key so that it can uniquely identify the records in a table. If LightSwitch cannot infer a primary key, it hides the table from the dialog that's shown in Figure 2-19. LightSwitch uses columns that do not accept null values to infer the primary key. Figure 2-20 illustrates this behavior when you attach a table with no primary key to your application. So, to attach a table that’s missing from the “Choose your Database Objects” dialog, you should define a primary key on the table at the database level.

Figure 2-20.  LightSwitch infers the primary key for a table based on columns that do not allow nulls

Refreshing Data Sources If the location of your database server changes, or if the schema of your tables changes, you can refresh your LightSwitch model by right-clicking your data source and choosing the “Refresh Data Source” option. When the wizard appears, you can update your database connection details by returning to the very first page in the wizard. Although you can change the connection string from one database server to another, you can’t change the underlying data provider. For example, you can’t change from SQL Server to MySQL without deleting the tables in your application and re-importing. If the wizard detects any table changes, it indicates them by using a red cross or an exclamation point (shown in Figure 2-21).

35

Chapter 2 ■ Setting Up Your Data

Figure 2-21.  Database objects dialog showing changed items When you click the Finish button, the wizard updates all screens and removes controls that are bound to the deleted fields. However, it won’t update any references to those fields that exist in code. If references exist in code, they’ll become invalid and will show up in the Error List window. At this point, you can work through the error list and resolve any remaining errors.

Unsupported Data Types When you connect to an existing database, you will notice that there are four SQL types that are currently unsupported. These are the spacial data types geography and geometry, as well as hierarchyid and sql_variant. If a table in your existing database uses any of these data types, LightSwitch won’t be able to read or write to those fields.

Attaching to SharePoint Data You can connect your application to a SharePoint 2010 (or higher) data source. LightSwitch uses a custom OData provider and, therefore, it doesn’t support versions that are from prior to SharePoint 2010. You can attach to SharePoint lists using the Data Source wizard in the same way that you would connect to SQL Server data. There are various limitations when you attach to a SharePoint data source. First, LightSwitch cannot manage SharePoint attachments or documents. Second, there’s limited support for the SharePoint column types of Picture and Hyperlink. This is because there are no native controls to display these data items. Multi-line text is also not fully supported because there is no native HTML control available to edit the content.

36

Chapter 2 ■ Setting Up Your Data

Deleting a Data Source If you delete a data source, LightSwitch removes all entities that relate to that data source from all screens in your application. The screens themselves will not be deleted, but instances of entities and related controls within those screens will be removed.

Defining Relationships between Data Sources Although it might not seem obvious, you can define relationships between tables in the Intrinsic database and tables in external data sources. By defining relationships, you can use data controls on the screens that you design. In case you’re worried about damaging your attached data source, there’s no need. LightSwitch won’t make schema changes to your attached data source when you define relationships between it and the Intrinsic data source.

Creating Computed Properties Computed properties are special properties that derive their values through calculations and possibly from other fields. Computed properties are read-only by definition and appear in the entity designer with a calculator icon next to the field. For desktop client applications, LightSwitch computes the calculated property value on both the client and the server. From a practical point of view, this means LightSwitch can recalculate and display immediately the value of a computed property on screen without requiring any intervention that triggers a server event, such as a user clicking the Save button on the screen. It’s important to note that HTML client screens cannot display computed properties. Computed properties are defined with .NET (VB or C#) code. The HTML client is incompatible because it uses the browser’s JavaScript engine for computational tasks. To further explain how computed properties work, I’ll now show you some examples. This will give you an idea of the type of code that’s involved in constructing a computed property. In subsequent chapters, you’ll find out how to display the computed property values in screens.

■■Tip There’s nothing to prevent you from creating a computed property on an attached table. Computed properties are not just limited to tables that you create in the Intrinsic database.

Creating Summary Properties For each table, you can specify a summary property through the properties sheet in the table designer. Summary properties are designed to summarize the contents of a data row for display purposes. To show a summary property on a screen, you use a summary control. This control is most often used in grids and auto-complete boxes. The example that follows shows you how to create a computed property in the Engineer table called FullName that concatenates the first name and surname of an engineer. To create this computed property, open the Engineer table and create a new property called FullName. In the General section of the properties sheet for the new property, check the “Is Computed” checkbox. Click on the “Edit Method” hyperlink and enter the code that’s shown in Listing 2-1.

37

Chapter 2 ■ Setting Up Your Data

Listing 2-1.  Formatting strings in a computed property

This code demonstrates how to format strings using .NET’s String.Format method. This method accepts two arguments. The first argument specifies the string to be displayed and includes placeholders in the format {0},{1} and so on. The second argument is a comma-separated list of data items that are then substituted into the display string. To set this as the summary property, open the properties sheet for the Engineer table and choose FullName from the summary property dropdown (Figure 2-22 ).

Figure 2-22.  Summary property set to a computed field Figure 2-22  shows the Full Name Summary on a screen that is designed for entering new issues.

■■Note  LightSwitch stores computed property code in the folder Server\DataSources\ApplicationData\. For projects that you upgrade from earlier versions of LightSwitch, you'll find the computed property code in the folder Server\Usercode\Shared\.

Calculating Dates with Computed Properties You can use computed properties to calculate dates. This example shows you how to calculate the difference between two dates. The Engineer table contains a date of birth field. By using a computed property, you can calculate the age of a person in years. To do this, create an integer-computed property called Age and enter the code as shown in Listing 2-2.

38

Chapter 2 ■ Setting Up Your Data

Listing 2-2.  Calculating date differences

This code illustrates the use of the VB.NET DateDiff function. This function allows you to accurately calculate date and time differences, and also takes leap years into consideration. C# doesn’t have an equivalent method, and the calculation is therefore slightly more complex.

■■Caution The Silverlight client caches data from the server. Therefore, Computed Properties that refer to data can produce incorrect results, especially those that calculate real time data (e.g. the number of minutes since a support issue was opened).

Summarizing Child Records with Computed Properties You can easily refer to related records by using navigation properties. In this example, we will create a computed property in the Engineer table that returns the number of help desk issues that are assigned to each engineer. To do this, create a computed property called IssueCount and enter the code shown in Listing 2-3. Listing 2-3.  Using navigation properties in a computed property

39

Chapter 2 ■ Setting Up Your Data

The code in Listing 2-3 demonstrates how to refer to child items in a computed property. Specifically, it shows you how to use the aggregate count operator against a navigation property. Other useful aggregate operations you can use include Sum and Average.

Returning Images with Computed Properties You’re not just limited to returning string and numeric data in a computed property. This example shows you how to create a computed property that returns an image. If the current date exceeds the target end date, this computed property returns a warning icon. Otherwise, it returns a blank white image. To create this example, create an image field called Icon and enter the code shown in Listing 2-4. Listing 2-4.  Creating a computed property that returns an image

This computed property returns a hardcoded, base-64 encoded image. You can find various websites where you can upload an image and find out its base-64 encoding. Alternatively, you can retrieve the image from a table. Figure 2-23 shows an example of how this computed property appears on a data grid.

40

Chapter 2 ■ Setting Up Your Data

Figure 2-23.  A computed column that returns an image

Sorting and Filtering by Computed Properties A slight limitation of computed properties is that you can’t sort or filter by these fields. If you create a query that uses a table with computed properties, these fields will not appear in the drop-down list of available fields when you try to add a filter or sort condition. If you need to sort grids by computed properties, a possible workaround is to use a SQL Server computed field rather than a LightSwitch computed property. This approach will only work with data in an external SQL data source. Furthermore, SQL Server computed columns are less powerful because you can’t refer to data in other tables. If you want to sort a table by a computed value, you can do this by creating a query and writing code in the PreProcessQuery method. Chapter 10 describes this type of code in more detail.

Summary LightSwitch provides two methods you can use to add data to your application. You can either create tables in the built-in Intrinsic database or you can connect to an existing data source. A single LightSwitch application can connect to multiple data sources, and you can work with almost any data source that you require. This is because, if LightSwitch doesn’t support your data source, you can write your own RIA Service or custom data source extension to access your data. The data sources LightSwitch natively supports include SQL Server, SharePoint, OData, SAP, and RIA. While you’re developing your application in Visual Studio, LightSwitch hosts your Intrinsic database using LocalDB (the successor to SQL Server Express). LightSwitch persists any data you add at design time between debug sessions. However, note that there isn’t a built-in way to deploy your design-time data to your live SQL Server environment. In terms of terminology, LightSwitch uses the word entity to refer to a row of data from a table. A property refers to a field or column in a table. You can store your data using standard data types, such as strings and integers. But unlike with other databases, you can also store rich data types like web addresses, phone numbers, and email addresses. These data types are called business types. They provide custom validation and specialized data-entry controls, and you can take advantage of these features by simply setting the type of a field to a business type. Business types use native data types for their underlying storage. This means that they’re not limited to fields in your Intrinsic database. You can also apply business types to table fields that belong to attached data sources. You can set up relationships between tables, even if your tables belong to different data sources. It’s important to define relationships on your tables; otherwise, you’ll find it very difficult to design screens later on.

41

Chapter 2 ■ Setting Up Your Data

If you want your users to enter data by choosing from a list of predefined selections, you can either use a related table or create a choice list. Choice lists are ideal for storing static lists of data that rarely change. For each row in a table, you can carry out some math or computational logic and expose the result as a computed property of the row. To give an example, for a table that stores the date of birth of individuals, you can create a computed property that returns the age for each individual. Computed properties aren’t just limited to tables in your Intrinsic database. You can also define them on tables in attached databases. One caveat is that you can’t sort or filter collections of entities using computed columns. Another important point is that you can’t display the value of computed properties in HTML client applications.

42

Chapter 3

Building HTML Applications Given the wide adoption of tablet and smartphone devices in corporate environments, a crucial part of application design is mobile support. LightSwitch can help you with this task. With LightSwitch, the HTML client applications you build are HTML5 compliant and fully optimized to operate on mobile devices. In this chapter, I’ll introduce the topic of HTML client application design and show you how to do the following: •

create screens to display lists of data and individual records



lay out screens, use data-entry controls, and use data-picker controls



construct menu navigation items and provide links to open records

LightSwitch provides screen templates to automate the UI creation process. In this chapter, you’ll find out how to use these templates to build a working application. Afterward, I’ll show you how to use the screen designer to further customize the screens you create. A piece of good news is that this chapter contains no code. The intention of this is to highlight how much you can accomplish by using the graphical designer alone.

Building an HTML Application This chapter extends the Help Desk application from Chapter 2. In this chapter, I’ll show you how to create a screen to enter issue records. Each issue record can be assigned to a specific engineer. In addition to learning how to create screens for data entry, the main purpose of this section is to show you how to associate a record with a “parent” record from a lookup table, and how to display lists of records on a screen. With LightSwitch, creating these types of screens is a simple affair that involves filling in some details on a dialog and clicking an OK button. But behind the scenes, the screens that LightSwitch generates can be quite complex. So, in the subsequent part of this chapter, I’ll deconstruct the screens that LightSwitch generates to show you how all the parts tie together.

Creating Screens A LightSwitch screen is analogous to a web page. Screens contain content and controls that users can use to edit and view data. A typical LightSwitch application consists of many screens. Screens run on the browser and are therefore client-side objects. Therefore, within your solution, the HTML client project is the place where you develop and manage your screens. To create a screen, right-click your HTML client project in Solution Explorer and choose the “Add Screen” menu item. When the Add New Screen dialog opens (as shown in Figure 3-1), select a screen template and choose a data source from the Screen Data section of the dialog.

43

Chapter 3 ■ Building HTML Applications

Figure 3-1.  Adding a new screen LightSwitch uses the screen template and data source to build a screen that carries out a specific function. In general, the screen that LightSwitch builds serves as a starting point for further customization. The screen templates you can select are: •

Common Screen Set: this creates the three screens that are described beneath



Browse Data Screen: this creates a screen that displays a list of records



View Details Screen: this creates a screen that displays a single record



Add/Edit Details: this creates a screen that users can use to add or edit a single record

The Common Screen Set is particularly helpful because it creates a set of Browse, View, and Add/Edit screens for any selected table in your application. Earlier versions of LightSwitch didn’t include this template, which meant that you needed to run the Add New Screen dialog three times to accomplish the same result. You can use the Screen Data drop-down to set the data source for your screen; this drop-down shows a list of tables and queries. If the data source you choose includes related child data, the Screen Data section shows checkboxes you can select to add related data to your screen.

44

Chapter 3 ■ Building HTML Applications

■■Tip  You can create an empty screen by choosing the Browse Data Screen template and leaving the Screen Data drop-down set to “none.” An empty screen provides you with a blank canvas you can use to manually build your screen.

Walkthrough 3-1. Creating an Application The simplest way to explain how to create an application is to provide a walkthrough of the steps involved. In this walkthrough, I’ll show you how to build a set of screens for the Help Desk application by using the Common Screen Template. Afterward, I’ll describe how the application looks and behaves at runtime. This will be beneficial if you’ve never seen a working LightSwitch HTML client application before.

Using the Common Screen Template The quickest way to create a set of screens is to use the Common Screen Template. But before we do that, we need to set up our data. Here’s a reminder of how to create the tables that I described in Chapter 2. 1. Create a table called Engineer (Figure 3-2). Notice the data types and the required setting for each property in the table.

Figure 3-2.  Create a table called Engineer

45

Chapter 3 ■ Building HTML Applications

2. Next, create a table called Issue (Figure 3-3).

Figure 3-3.  Create a table called Issue 3. With the Issue table open in the table designer, create a relationship between the Issue and Engineer tables. Name your navigation property AssignedEngineer (Figure 3-4).

46

Chapter 3 ■ Building HTML Applications

Figure 3-4.  Relationship between Issue and Engineer tables With the table structure now set up, the next step is to generate screens for our two tables. To do this: 1. Open the Add New Screen dialog and add a new screen for the Engineer table. Select the Common Screen Set template. When you choose the Engineer table, the Screen Data section shows checkboxes for related data and gives you the option to include engineer issues. Check this option to include the issue data on your screen (Figure 3-5).

47

Chapter 3 ■ Building HTML Applications

Figure 3-5.  Creating screens for the Engineer table 2. Open the Add New Screen dialog and repeat the above process for the Issue table (Figure 3-6). Although the Additional Data to Include section includes a checkbox for Issue Details, there isn’t a checkbox to select the Engineer details. This is because LightSwitch only includes checkboxes for related child records.

Figure 3-6.  Creating screens for the Issue table

48

Chapter 3 ■ Building HTML Applications

Once you add these two sets of screens, LightSwitch organizes your screens into folders that are named after your tables (Figure 3-7). Beneath the Engineer folder, notice how the Common Screen Set template generates Add/Edit, Browse, and View screens for the Engineer table. These files are named AddEditEngineer.lsml, BrowseEngineer.lsml, and ViewEngineer.lsml respectively. The Issue folder also contains the same set of screens, but for the Issue table.

Figure 3-7.  LightSwich organizes your screens into folders In bigger projects with many screens, you can better organize your solution by creating new folders. The right-click menu item gives you the option to add new folders, and you can move screens between folders by dragging and dropping them.

Running Your Application Now that you’ve created a set of screens, you can run your application. To compile and run an application, click the green Play button in Visual Studio’s toolbar or press F5. When you do this, Visual Studio opens your application in Internet Explorer. LightSwitch displays a splash screen while your application loads, and when it’s ready, it opens the screen that you define as your “home screen.” By default, this is the first screen that you add to your application. So, in this example, the Browse Engineer screen is the first screen that appears.

49

Chapter 3 ■ Building HTML Applications

Figure 3-8 shows the Browse Engineer screen once it’s been populated with records. The purpose of this illustration is to highlight the main characteristics of a screen that’s based on the Browse Data Screen template. The header of the screen displays the screen title. Next to this is a navigation drop-down that switches the view to other screens that are configured to browse data.

Figure 3-8.  LightSwitch’s Browse screen The central part of this screen features a tile list control. This is a control that renders the records from left to right, then top to bottom. When a user clicks a tile, the application opens the record in the View Details screen. The screen’s footer contains two buttons: Add and Search. The Search button reveals a textbox at the top of the screen that users can use to enter search criteria (Figure 3-9). For search operations, LightSwitch matches the search criteria against text fields where the Is Searchable checkbox is selected in the table designer. One caveat is that this search feature doesn’t match against date fields, or text fields in related tables. If you want to provide more sophisticated search functionality, you can find out how to do this in Chapter 10.

50

Chapter 3 ■ Building HTML Applications

Figure 3-9.  Searching for records The Add button opens a screen that users can use to add a new record (Figure 3-10). The LightSwitch term for this type of screen is a Dialog screen. This type of screen opens as a lightbox; this describes a panel pop-up that appears over the existing screen, with the underlying screen darkened.

Figure 3-10.  Adding a new record—an example of a Dialog screen

51

Chapter 3 ■ Building HTML Applications

In addition to data-entry controls, the Dialog screen includes Save and Cancel buttons in the top right section. The screen automatically applies basic validation. For instance, users can’t save records with invalid email addresses or dates of birth. Once a user successfully saves a record, the application returns to the previous screen—in this case, the Browse Engineer screen. Let’s look at the screen that users use to enter new issue records. Just like the Add Engineer screen, this screen contains data-entry controls. To associate an issue record with an engineer, the user utilizes a details modal picker control, as shown in Figure 3-11. This control appears modally above the existing screen and shows a list of engineers that the user can choose from.

Figure 3-11.  Using the modal picker Control Once you add issue records that are assigned to an engineer, you can open the Browse Engineer screen, open an engineer record, and see the issues that are assigned to the engineer you select. The View Engineer screen that opens includes a tab control along the top of the screen. The title text on this control switches the view between the Details and Issues tabs. With the Issue tab activated, you can see a list of all issues that are assigned to the engineer (Figure 3-12). In this screenshot, notice also how LightSwitch sets the title of the screen to the name of the engineer.

52

Chapter 3 ■ Building HTML Applications

Figure 3-12.  Issue tab on an engineer record that shows associated child records This exercise has given an overview of how to create a LightSwitch application, and also highlights the ease at which you can build an application without the need to write code. The application provides add, edit, and search functionality. It also includes some non-trivial features, such as the ability to associate a parent engineer record with an issue record, and the ability to show child issues that are associated with an engineer record.

Using the Screen Designer You’ve just seen how simple it is to create a fully functioning LightSwitch application. The Common Screen Set template carried out all the work for you, so in this section, I’ll describe the screens that were generated by the template. By the end of this section, you’ll have gained a deeper understanding of how screen design works.

Understanding Top-Level Screen Layout The tool you use to build and customize screens is the screen designer. Let’s take a look at this by opening the Browse Issue screen. To do this, double click the Issues. lsml file, and when the screen opens, you’ll see the view that’s shown in Figure 3-13.

53

Chapter 3 ■ Building HTML Applications

Figure 3-13.  The screen designer in LightSwitch The screen designer consists of nodes that resemble a tree structure—these nodes represent UI elements on your screen. If you’re more familiar with other development tools such as Microsoft Access or Windows Forms, this method of screen design might feel odd, because you don’t see a visual representation of how your screen looks at runtime. However, don’t worry. After a while, this method of screen design will become second nature. Working from the top of Figure 3-13, the topmost item is the screen designer toolbar. Beneath this toolbar, you’ll see the root node, followed by layout of your screen as a series of nodes. These tree nodes consist of a combination of layout controls and data controls. Layout controls are designed to add structure to your screen, whereas data controls describe controls that users can use to view or edit the fields in your tables. The lower part of the Screen Content Tree contains a Popups node you can use to define popups. Popups are small modal UI dialogs that pop up over a screen, hence the name. Chapter 8 will cover this topic in further detail. To give an example of where to use a popup, you could use one to ask for user confirmation prior to a user deleting a record. The left part of the screen designer contains the data items you can use on your screen. Here, you’ll find a list of tables and/or queries, as well as their constituent fields. This part of the screen designer is called the screen member list. To display data on a screen, you would drag a data item onto the Screen Content Tree and then set the data control that you want to use to render your data. This means that every control on a screen must be bound to a data item. Unlike other development tools such as Windows Forms, you can’t just add a label or textbox to a screen and leave it unbound to data.

54

Chapter 3 ■ Building HTML Applications

■■Note  When you make changes to a screen in the designer, you can see your changes by refreshing your browser. There’s no need to recompile and restart your application in order to see screen modifications.

Using the Screen Designer Toolbar The Screen Designer Toolbar contains buttons you use to carry out common screen design tasks. There are seven buttons, which are shown in Figure 3-14.

Figure 3-14.  Screen Designer Toolbar Working from left to right, the Edit Query button doesn’t apply when you’re building HTML applications; the button is actually grayed out. This button only becomes active when you build desktop (Silverlight) applications, and the purpose of this button is to allow you to edit the underlying screen query. The Add Data Item button opens a dialog you can use to add additional properties, queries, and commands onto your screen. You can use the Add Layout Item and Delete buttons to modify the items that are shown in the Screen Content Tree. When you right-click a node in the Screen Content Tree, the context menu provides the same features that are offered by these buttons. The Reset button provides a really useful function. If you add extra fields to your table, this button resets the controls in a selected group back to their default state. It automatically adds controls for the new fields you’ve added and saves you from having to add them manually. The Write Code button opens the code editor and allows you to write JavaScript code to handle screen events. Finally, the Related Items button provides a shortcut you can use to open the tables in your screen in the table designer. This button saves you from having to navigate your way through Solution Explorer to get to your tables.

Using Tabs Tabs are UI containers that fill the entire working area of a screen. You can use Tabs to better organize your screen by grouping related controls together. Figure 3-15 shows the Engineer View screen at both design time and runtime. Each node beneath the Tabs folder defines a separate tab. The Add Tab button adds an additional tab to your screen.

55

Chapter 3 ■ Building HTML Applications

Figure 3-15.  Tabs at design time and at runtime The Engineer View Screen that we created earlier demonstrates a perfect use of tabs. The first tab contains the engineer details and the second tab contains a list control that shows the issues that are assigned to the engineer. The end user can switch tabs by clicking the tab heading that appears on the tab control.

Laying Out Your Screen with Group Controls With LightSwitch, you can use groups to lay out the data items on your screen. Once you add a group, you can render the group using one of two controls: rows layout and columns layout. The rows layout control lays out controls from top to bottom, whereas the columns layout displays controls horizontally from left to right (or right to left if you localize your application in a right-to-left language). To achieve a more granular layout, you can nest groups inside one another. Figure 3-16 illustrates how these controls apply in the Engineer View screen. The highlighted section of this screenshot features a columns layout group that contains two child-rows layout groups.

56

Chapter 3 ■ Building HTML Applications

Figure 3-16.  Using both Rows Layout and Columns Layout groups on a screen In the properties sheet for a group control, you’ll find a checkbox option to enable compact margins. When you set this option to true, LightSwitch renders the controls on your screen closer together, as illustrated in Figure 3-17.

Figure 3-17.  Compact margins enabled/disabled

57

Chapter 3 ■ Building HTML Applications

Using Data Controls Data controls are UI elements that users can utilize to view or edit data. LightSwitch provides a variety of data controls, which are shown in Table 3-1. Table 3-1.  Data Controls

Name

Description

Supported Data Types

Text

Use this to display read-only text.

All LightSwitch data types

Paragraph

Similar to the text control, this control displays read-only text. But unlike the text control, you can configure the height of the control.

All LightSwitch data types

TextBox

Text boxes allow users to enter a single line of text.

All LightSwitch data types

TextArea

Text areas allow users to enter multiple lines, including line breaks.

All LightSwitch data types

Date Time Picker

The date time picker control allows users to enter and view dates and times.

Date, Date Time

Email Editor

Enables users to enter email address and provides validation

Email Address business types

Email Viewer

This displays an email address in a read-only fashion. Web Address/Email Address business types

WebAddress Viewer

This displays a web address in a read-only fashion.

Flip Switch

Allows user to set Boolean true/false or yes/no values Boolean

Web Address/Email Address business types

You can only select data controls that are compatible with the data type of the data item you want to display. Table 3-1 shows the data types that are supported by each data control. I’ll now describe in greater detail the controls that you can use in an application.

Showing/Editing String Values String data is perhaps the most common data type in most applications. In LightSwitch, you can categorize the controls that render string data into editable and non-editable controls. To enable users to edit data, the controls you can choose from are text box and text area (Figure 3-18). The difference between these two controls is that the text box control enables single-line text entry whereas the text area control permits multi-line text entry.

58

Chapter 3 ■ Building HTML Applications

Figure 3-18.  Text boxes render as HTML inputs; text areas render as HTML text areas Likewise, when you want to display data in a read-only fashion, the text control is designed to display single-line text whereas the paragraph control can display multi-line text. In terms of the markup that LightSwitch generates at runtime, the screen uses the HTML tag to display the content of a text area control, and uses the markup tag to render the contents of a text box control. Returning briefly to the screen designer, there are a couple of significant settings that you’ll find in the properties sheet (Figure 3-19). The first is the Display Name setting. The value you enter here appears in the label that appears against the control. The second is the Placeholder setting. The text you enter here appears as a “watermark” when the control is empty, and you typically use this to provide help and guidance to the user. As soon as a user types into the control, the placeholder text disappears.

Figure 3-19.  Properties of a data control

59

Chapter 3 ■ Building HTML Applications

Some web developers often use tooltips to provide context-sensitive help. The problem with tooltips is that they don’t work on mobile devices, because the UI on mobile devices don’t include a cursor. Therefore, placeholder text is the ideal solution for providing context-sensitive help.

Working with Boolean Values LightSwitch provides a flip-switch control for setting Boolean values. Figure 3-20 illustrates the appearance of this control at runtime. You can configure the text within the flip-switch control to show either on/off or yes/no. The Options setting in the properties sheet controls this setting.

Figure 3-20.  The flip-switch control at runtime and design time On the read-only View Engineer screen that we created with the Common Screen template, LightSwitch uses a text box control to display read-only versions of any Boolean properties on the table. The text box control displays Boolean values by using the text values true and false. There isn’t a simple option to change the label text to on/off or yes/no in order to make the data on the text box control consistent with the options that are shown on the flip-switch control. If you want to customize the text that describes a Boolean value, you’ll need to add a custom control, which I’ll show you how to do in Chapter 8.

Showing/Editing Date Values The date picker control allows users to enter and edit dates and times. You can configure the date picker through the properties sheet for your data item. The date picker enables users to enter the date parts by choosing from a list of values. A useful setting is the Minute Increment setting, which defaults to 5 (Figure 3-21). This configures the minute picker to show the values 0,5,10,15,20,25,30 (and so on), rather than the values 0 through to 60.

60

Chapter 3 ■ Building HTML Applications

Figure 3-21.  Date time picker control properties, including Minute Increment setting You can use the text control to display dates in a read-only fashion. But similar to showing Boolean values through a text control, LightSwitch applies a default format that doesn’t look very neat. Once again, you can use a custom control to apply better formatting.

Showing/Editing Email or Web Addresses The email address editor control enables users to enter and edit email addresses. The difference between this and the text control is that the email editor control prevents users from entering invalid addresses by including built-in validation. The email address viewer control is designed to display email addresses. This control displays the email address as a hyperlink that opens the user’s default email client. Similarly, the web viewer control is designed to display web addresses. It renders the web address as a hyperlink that opens the page in the browser.

Showing Lists of Records There are three controls that you can use to display lists of records—the list, tile list, and table controls. The difference between the list and tile list controls is that the list control renders data items from top to bottom, whereas tile list renders data items from left to right, then top to bottom (Figure 3-22).

61

Chapter 3 ■ Building HTML Applications

Figure 3-22.  Tile list view versus list view The table control organizes data into rows and columns. This control renders data using an HTML table, and uses TR and TD tags to render the table rows and cells. A feature of the table control is that it behaves reactively. On mobile devices with limited width, the table control stacks the data rather than show it in a tabular format (Figure 3-23).

Figure 3-23.  Table control—illustration of reactive behavior

62

Chapter 3 ■ Building HTML Applications

A feature of these data controls is infinite scroll. If a user hypothetically loads a screen that includes 1,000 records, LightSwitch doesn’t load all 1,000 records upfront. Instead, it loads the records on-demand as the user scrolls through the screen. LightSwitch loads the records in batches, and you can modify this behavior by setting the “No. of items to display per page” setting in the properties sheet (Figure 3-24).

Figure 3-24.  Page list setting For all these controls, you can set the data that’s shown for each record by modifying the child nodes. For example, the Browse Engineer screen that the template created shows the Issue Description, Assigned Engineer, and Date Issued fields. To tidy this up, you can add or remove data items from beneath the rows layout (Figure 3-25).

Figure 3-25.  Changing the items that appear in a list/tile control

63

Chapter 3 ■ Building HTML Applications

Alternatively, you can change the rows layout to a summary control. This control shows the summary field you define for a table. For instance, if you set the summary property on the Issue table to the Issue Subject property, the summary control will show the Issue Subject value for a record at runtime. A benefit of using the summary control is that if you use it multiple times in your application and you later want to change the data that’s shown by the control, you only need to make a change in one place—the table designer.

Using Data Picker Controls The details picker control is a control that enables a user to choose one item from a list of records (Figure 3-26). Just like the list controls, you can modify the content that’s shown for each record in the list by replacing the details picker’s summary control with a rows layout, and adding data items beneath the rows layout.

Figure 3-26.  Details picker control The details picker control provides a built-in search feature. Users can carry out a search by typing search criteria into the control. LightSwitch carries a “contains”-type search against the search criteria. To limit the items that are shown by picker control, you can set the Choices setting in the properties sheet. The Choices setting enables you to select a query that you’ve added to your screen through the Add Data Item button from the toolbar.

Positioning Controls Earlier on, I showed you how to use the row and column layout controls to set the orientation of groups of controls. To fine-tune your layout, you can use the properties sheet to configure the sizing and positioning of each control on your screen. Figure 3-27 shows the sizing properties that you can set.

64

Chapter 3 ■ Building HTML Applications

Figure 3-27.  Sizing options Most of the options in the sizing section of the properties sheet are self-explanatory. For instance, the Width and Height settings default to Auto. This means that LightSwitch chooses an optimal width and height based on the screen space that’s available. If you want to specify a definite size, the units that you can use are pixels or characters and lines. For each data control you add to your screen, LightSwitch displays a label. If (for example) you add a surname text box to a screen, LightSwitch displays a surname label next to the text box. As I mentioned earlier, the text value for the label comes from the Display Name property that you configure in the table designer. Figure 3-28 shows the Label Position dialog. These include Top, Left, and Right; these options are self-explanatory. But an interesting pair of options are None and Hidden. The difference between these two is that when you set the label position to Hidden, LightSwitch still shows the space that the label would have taken. By default, LightSwitch top aligns labels. One benefit of top alignment is that it simplifies the task of localization. If you localize an application by substituting English text with a foreign translation, you’ll suffer fewer layout problems with top-aligned labels if the target word in the foreign language is longer than the English equivalent.

65

Chapter 3 ■ Building HTML Applications

Figure 3-28.  Label Position dialog You can also set the Text Alignment value for a control through the properties sheet; the available options are Left, Right, or Center. As an example of where you might use this setting, it’s common practice to set the text alignment to Right for numeric fields.

Setting Screen Properties You can set your screen’s display name and control the visibility of the tab control through the properties of the Root Node (that is, the very first item in the Screen Content Tree). Figure 3-29 shows these settings and the effect they have on a screen at runtime.

Figure 3-29.  Setting screen properties

66

Chapter 3 ■ Building HTML Applications

The properties sheet contains three groups. Starting from the top, the General group contains controls to set your screen’s display name and description. The display name is the text that appears at the top of your screen. LightSwitch doesn’t show the description that you enter here to the user. Therefore, you can generally leave this field blank or use this field to enter comments for your own development purposes. The Appearance group contains two checkboxes: Show As Dialog and Hide Tab Titles. Earlier in this chapter, you saw how LightSwitch opens the Add Engineer screen as a lightbox, with the underlying screen dimmed. The Show As Dialog checkbox is the setting that enables this behavior. By checking the Hide Tab Titles checkbox, LightSwitch shows only the contents of the first tab and hides the tab titles. By definition, this prevents users from switching tabs, because the tab title is the control that enables users to switch tabs. You might wonder why you’d choose to hide the tab titles. One reason is that you can define multiple screen layouts in separate tabs. You can then write code that changes the tab that’s visible based on some condition. The Behavior section includes a Screen Type drop-down. This includes two options: Browse and Edit. Screens that you set to the Browse screen type can appear in the navigation menu that shows at the top of your application. In contrast, Edit screen types cannot be added to an application’s navigation menu. LightSwitch adds Save and Cancel buttons to screens that are defined as Edit screens. Browse screens don’t include these buttons.

Building a Navigation Structure A crucial part of good application design is navigation. A sensible menu structure and well-thought-out navigation links help users more easily find the features they want. In this section, I’ll show you how to set the items that appear in the menu of an application, how to open a child record from a screen, and how to specify the initial screen that appears when your application first opens.

Setting a Home Screen The home screen is the first screen that LightSwitch opens when your application loads. To set or change your home screen, right-click the screen you want to use in Solution Explorer and select the Set as Home Screen link (Figure 3-30). You can only select screens that are defined as Browse screens. You can’t set an Edit-type screen as your start screen.

67

Chapter 3 ■ Building HTML Applications

Figure 3-30.  Setting a home acreen

Configuring the Navigation Menu To specify the items that LightSwitch shows in the navigation menu, right-click your HTML client project and click the Edit Screen Navigation button. This opens the screen that’s shown in Figure 3-31. By default, LightSwitch automatically adds all Browse-type screens you create to the navigation menu. You can rename the text that appears in the navigation menu by using right-click ➤ rename menu item.

Figure 3-31.  Configuring a home screen

68

Chapter 3 ■ Building HTML Applications

The right-click menu also includes a Delete option you can use to remove a screen from the navigation menu. Note that the Delete option doesn’t delete the screen; it only removes the entry from the navigation menu. Deleting items from the navigation menu can be useful for hiding work in progress, or for hiding old versions of screens that you want to keep as a backup. If you remove screens from the navigation menu, you can use the Include button to add those screens back into the navigation menu. Note that it’s possible to add the same screen into the menu structure multiple times.

Navigating to Different Screens With the Browse screens in our application, users can click a record in the tile control to open the record in a View screen. The place where you control this behavior is through the properties of the tile control. The Actions group includes an Item Tap property that’s set to a method called viewSelected. To change what happens when a user clicks a record in the tile control, click the viewSelected link. This opens the Edit Item Tap Action dialog, as shown in Figure 3-32. This dialog provides a radio option you can use to write custom JavaScript code, or you can choose from a list of pre-built methods. This list is organized into two sections—a section that groups together record operations, and a section that’s titled Navigation. So, in the case of the Engineer Browse screen, the two sections in the list are Engineers and Navigation.

Figure 3-32.  Edit Tap Action dialog The Engineers section includes options to view, edit, or add and open the newly added record in the Edit screen. Once you’ve selected one of these options, you need to specify a target screen from the Navigate To drop-down.

69

Chapter 3 ■ Building HTML Applications

Adding Navigation Buttons The Command Bar section in the screen designer controls the buttons that appear in the bottom right part of a screen (Figure 3-33). Once you expand the Command Bar section, you can add additional buttons or modify the behavior of existing buttons. You can define what happens when a user clicks a button by using the Tap Action dialog. The options you can choose in this dialog include showing the search textbox, editing an existing record in a new screen, or adding a new record.

Figure 3-33.  Edit Tap Action Dialog If you want to add a button that appears in-line on your screen (rather than in the Command Bar section), you can do so by right-clicking a group control and selecting the Add Button option.

Changing Button Icons For any button you add to the Command Bar section, you can change the icon through the setting in the properties sheet. There are 32 icons that you can choose from, and these are shown in Figure 3-34.

70

Chapter 3 ■ Building HTML Applications

Figure 3-34.  List of available icons If you choose the Custom option, you can define your own button image by writing custom code, which I’ll show you how to do in Chapter 8.

Summary This chapter showed you how to create a data-centric HTML application without needing to write any code. This chapter has also introduced you to the screen designer. When you create a screen, you can use one of the four built-in template types. Templates allow you to build screens with a prebuilt layout and function. The built-in templates include Browse Data, View Details, Add/Edit Details, and Common Screen Set. The Browse data template creates a screen that displays a list of records. The View details screen template creates a screen that shows a single record, while the Add/Edit details screen template creates a screen to allow users to create or update records. A really helpful screen template is the Common Screen Set template. For any given table, this template creates all three of the other screens, including all the navigation logic. This is useful because you can implement browse, add, and update functionality for any given table at a click of a button. The screen designer in LightSwitch is made up of a tree that contains nodes that represent group or data controls. Group controls organize the controls that appear on your screen, and there are two controls you can use: rows layout and columns layout. The rows layout control lays out its child controls from top to bottom, whereas the columns layout control lays out its child controls horizontally from left to right. You can lay out your screen more precisely by nesting these group controls. Also, you can further organize a screen by using tabs to separate groups of common controls.

71

Chapter 3 ■ Building HTML Applications

A crucial part of the screen designer is the Screen Members list. This item appears on the left-hand side of the screen designer and shows the queries, tables, and data items you can use on your screen. To add a data item to your screen, you can simply drag the data item from the Screen Members list onto your screen layout. At runtime, LightSwitch renders data items using data controls; these are controls that users can use to view and edit data. The controls that render scalar data include the text, paragraph, text box, text area, and date time picker controls. To display lists of multiple records, you can use the tile list, list, or table controls. Another type of control is the details picker control. This control enables users to select a record from a list, and also includes a search feature to help users more quickly locate a related record. Through the properties sheet for a screen, you can set the screen type to one of two settings: Browse or Edit. Browse-type screens are designed to show lists of records, and can appear in your application’s navigation menu. Edit screens are designed to work with a single record and open as a panel, or lightbox, that appears above the existing screen. LightSwitch displays a navigation menu that appears in the top left part of your application. Users can use this menu to switch screens, and you can control the screens that appear in this menu through the properties section of your HTML client project. To build additional methods of navigation into your application, you can configure what happens when a user clicks a record in the list, tile list, or table controls. You can also implement navigation by adding buttons to your screen. In either case, you use the options that appear in the Tap Action dialog to define what happens when a user clicks a control.

72

Chapter 4

Creating Desktop Applications With LightSwitch, you can build Silverlight-based “desktop” applications that run either on desktops or inside browsers. These applications work well on PCs and are characterized by rich features such as data grids, data-export functionality, and tight integration with the desktop. Here are the main topics that I’ll cover in this chapter: •

the pros and cons of Silverlight versus HTML client applications



how to create screens, layout controls, and configure screen navigation



how to present data using built-in data controls

In this chapter, I’ll show you how to develop a desktop application with the same functionality as the HTML application you created in Chapter 3. Just like the previous chapter, this chapter emphasizes the simplicity of LightSwitch by intentionally containing no code.

What This Chapter Covers In the first part of this chapter, I’ll show you how to build a desktop version of the Help Desk application. The application includes Data Entry screens for both engineer and issue records. To manage existing records, we’ll add Grid screens to display multiple records and Search screens to help users find existing records. When a user clicks a record in a grid, the specified record opens in a separate screen. Just like the HTML application, the Issue screen will include a picker control that you can use to assign an engineer, and the Engineer screen will contain a grid that shows the issue records that are assigned to the engineer. Figure 4-1 illustrates some sample screens and highlights the typical look and feel of a desktop application.

73

Chapter 4 ■ Creating Desktop Applications

Figure 4-1.  Example screens we’ll create in the first section

What Are the Benefits of Desktop Applications? Before moving on, let’s examine some reasons why you would choose to develop a desktop application. This question is particularly pertinent. You can just as easily build HTML client applications that are compatible with a wide range of devices, and given that HTML5 has a more certain future compared to Silverlight, what exactly are the benefits of building a desktop application? A big benefit of desktop applications is that they cater to corporate users who prefer the familiarity of a desktop application. But that’s not the only advantage. Unlike the HTML client, you can tightly integrate desktop applications with other programs that run on the client PC, such as Microsoft Office, or devices such as barcode scanners or receipt printers. Desktop applications can also include richer user interfaces, such as grids, and a tabbed, multi-document interface. These features are valuable for office workers, because they allow users to multi-task and to more easily compare and work with multiple records. For you, the developer, the benefit of Silverlight is that you can write your application with .NET code throughout. Unlike with HTML client applications, you don’t need to use .NET on the server and then switch to JavaScript when you work on the client. To build more sophisticated applications with the HTML client, you need to understand HTML, CSS, and jQuery. So, for developers who are just starting out, desktop applications are simpler to understand. Finally, if you want to manipulate and work with data on the client, Silverlight provides the ability to use LINQ. Manipulating data with JavaScript on an HTML client application without the use of LINQ is a much more difficult proposition.

74

Chapter 4 ■ Creating Desktop Applications

Creating a Desktop Client Let’s now begin to build our desktop application. The first step is to create a project. You can either create an entirely new project using the New Project template or you can add a desktop (Silverlight) client to your existing HTML project (Figure 4-2). Be aware that if you do the latter you won’t be able to host your existing HTML client in SharePoint.

Figure 4-2.  Creating a desktop application

Setting the Application Type You can configure your application as either a desktop or a web application. To set the application type, rightclick your client project, select Properties, and configure the Client Type setting, as shown in Figure 4-3.

Figure 4-3.  Setting the client type Just so that there’s no confusion, the Web radio option in Figure 4-3 configures your application as a Silverlight browser-based application, rather than as a full-fledged HTML web application. As I mentioned in Chapter 1, the biggest benefit that a desktop Silverlight application provides over a web-based Silverlight application is rich integration with other desktop applications through COM automation.

75

Chapter 4 ■ Creating Desktop Applications

If your intention is to build an application that runs in a browser, you could choose to create an HTML Client application as opposed to a Desktop Web application. An obvious question is “Why choose a Silverlight web application as opposed to an HTML client application?” One benefit is that you can create an application entirely using strongly typed .NET code. There’s no need to learn JavaScript, jQuery, CSS, or other web languages that you may be unfamiliar with. Another benefit is that desktop applications are based on a tabbed, multi-document interface and include support for grids. The ability to view and work with multiple records is a feature that many office workers appreciate. The biggest disadvantage of a web-based desktop application is that the end user needs to install the Silverlight runtime, and this dependency restricts the devices on which your application can run. For instance, your application won’t run on an Apple iPad because this device doesn’t support the Silverlight runtime.

Choosing a Screen Template Once you add a desktop project, you can begin to add screens. Just like with the HTML client, you can create screens by opening the Add New Screen dialog and choosing a screen template. But unlike the HTML client, the choices of templates are quite different, as you can see illustrated in Figure 4-4. Most notably, there isn’t a Common Screen Set template. This means that you can’t quickly add three screens in one go as you could with the HTML client (i.e., Browse, Add/Edit, and View screens). There’s also no Add/Edit Screen template. Instead, you typically must create separate View and Add/Edit screens using the Details Screen and New Data Screen templates.

Figure 4-4.  Adding a new screen with the Add New Screen dialog

76

Chapter 4 ■ Creating Desktop Applications

In most cases, the template names describe the purpose of each template. And if you need further explanation, the help text in the center of the dialog provides a fuller explanation. One screen template that warrants a bit more explanation is the List and Details Screen template. This template creates a screen that’s split into two main sections. The left part of the screen displays a list of records. When a user selects a record in the list, an editable version of the record appears in the right-hand pane. The Search Data Screen template is another template type that doesn’t exist in the HTML client. This template creates a screen that enables users to search for records. The screen shows the search results in a grid. Whichever template you choose, the Add New Screen dialog includes a Screen Data drop-down you can use to set the data source for your screen. If the data source you choose is related to other tables, the dialog shows checkboxes you can select in order to add the additional data to your screen. If you want to create a screen that isn’t bound to any data, choose the New Data Screen template and leave the Screen Data drop-down empty.

Walkthrough 4-1. Creating New Data Screens To demonstrate how to add Data Entry screens, this walkthrough will show you how to build two of them: one for entering engineer records and another for entering issue records. By building an application that contains two different entity types, you’ll see how to use auto-complete boxes and how to create screens that show related data. Before continuing, you’ll need to create the engineer and issue tables from Chapter 2. Once your project contains these two tables, you can create the Engineer Data Entry screen by following these steps: 1. First, open the Add New Screen dialog (as shown in Figure 4-4). From this dialog, select the New Data Screen template, choose Engineer from the Screen Data drop-down, and keep the default screen name of CreateNewEngineer. Because a relationship exists between the engineer and issue tables, the “additional data to include” section includes a checkbox you can use to select “Engineer Issues.” Make sure to choose this checkbox. When you click the OK button, LightSwitch adds the new screen to your client project and opens the screen in the designer. 2. For the time being, don’t make any changes to your screen. Instead, create a New Data screen for the Issue table by opening the Add New Screen dialog and selecting the Issue table from the Screen Data drop-down. 3. If your solution contains an HTML client, right-click your desktop project in Solution Explorer and select the “set as start-up project” option. You can now run your application by clicking the debug button in the toolbar or by pressing the F5 key. Figure 4-5 shows the application at runtime and highlights the appearance of the Create New Engineer screen. By default, this application uses the Cosmopolitan shell and theme. This shell features a menu in the top part of the screen that users can use to open Data Entry screens in your application. At present, this menu includes links that open the Create New Engineer and Create New Issue screens. Note that if you create screens that are based on the Details Screen template, they will not appear in this menu.

77

Chapter 4 ■ Creating Desktop Applications

Figure 4-5.  Running your application In Figure 4-5, notice how the data-entry controls are arranged in rows and columns. This arrangement is achieved through the use of group controls. The bottom part of the screen includes a command bar section that contains Save and Refresh buttons. By default, these two buttons appear on all the screens that you create. Finally, you’ll also notice that each screen opens in a separate tab. In desktop applications, users can open multiple screens at the same time and switch between open screens by using the tab control.

Designing Screens Let’s now open the screen designer and look at how to customize the screens that the screen templates generate. Figure 4-6 shows the Create New Engineer screen in design view.

78

Chapter 4 ■ Creating Desktop Applications

Figure 4-6.  Design view of screen The screen designer looks almost identical to the HTML client screen designer that I described in Chapter 3. As you’ll recall, the screen designer consists of a tree structure that includes group controls (such as row and column layouts) and data controls. Pertinent parts of the screen designer include the left-hand screen member list. This contains a list of the tables, queries, and properties that you can use on your screen. You can use the Add Data Item button from the toolbox to add items to this list. When you subsequently add new properties to a table, you can use the Reset button on the toolbox to reset the controls in a container block back to their default states. This saves you from having to manually add new fields to your screen one by one. To continue, I’ll summarize the more notable items that are shown in Figure 4-6.

79

Chapter 4 ■ Creating Desktop Applications

Setting Screen Properties You can configure various aspects of a screen by right-clicking the first node in the tree and using the settings in the property sheet (Figure 4-7).

Figure 4-7.  Root node properties A prominent setting you can set is the display name for your screen. At runtime, LightSwitch shows this piece of text in the screen’s tab title and also in the screen navigation menu. Note that you can override the display name setting in code, and, by default, screens that are based on the Details Screen template do this. The “Allow Multiple Instances” checkbox controls the ability of users to open multiple instances of a screen. If this is unchecked and the user attempts to open more than one instance, LightSwitch moves the focus to the screen that’s already open.

Grouping and Laying Out Controls Just like with the HTML client, you can use group controls to organize and position the data controls (e.g., text boxes, labels, checkboxes) on your screen. But unlike the HTML client, the desktop client provides a large choice of group controls. There are five controls: rows layout, column layout, tabs layout, group box, and table layout. The drop-down next to the node allows you to change control type; Figure 4-8 shows how these control types affect the screen layout at runtime.

80

Chapter 4 ■ Creating Desktop Applications

Figure 4-8.  Rows, columns, and table layout controls at design time and runtime To add a new group control, right-click a section of the tree and choose the “Add Group” option. You can change the group-control type by using the drop-down that appears next to the control. As Figure 4-8 shows, the rows layout container arranges controls, one beneath the other, whereas the columns layout places the controls side by side. The table layout arranges your controls in a tabular fashion. Each table layout contains one or more TableColumn layouts, and you add your data controls as child controls within a TableColumn layout. The group controls that exist only in the desktop client are the tab and group box layout controls. The tab control organizes your screen by separating groups of controls into separate tabs. To use the tab control, add a tab layout to your screen. Next, add child groups beneath the tab control—typically, you would add rows layout groups beneath the main tab control group. LightSwitch will render each group beneath the tab control as a separate tab, and it sets the tab title using the display name property you define for the group (Figure 4-9).

81

Chapter 4 ■ Creating Desktop Applications

Figure 4-9.  Tabs and group box layout controls The group box control tidies the appearance of your screens by placing a border around the child controls. The display name property of the group box control sets the title that appears on the control. In the example in Figure 4-9, the display name property of the group box is set to Personal Details.

Choosing Data Controls The Silverlight client provides a range of data controls you can use. These are UI elements that users can utilize to view and edit data. Although there are plenty of data controls, don’t worry if you can’t find a control that suits your needs. In such circumstances, you can create your own custom control. Table 4-1 shows a list of data editing controls. A popular one is the text box control. This is the default control that’s selected for editing string data. You can use a control only if it’s supported by the underlying data type. For example, you can’t assign the check box control to a string data property. So that you understand the appearance of some of these controls, Figure 4-8 shows the image, date picker, email, money, and phone number controls at runtime. Table 4-1.  Editable Data Controls

Name

Description

Supported Data Types

Text Box

Users can edit the data by typing into this control.

All LightSwitch data types

Check Box

Allows users to edit Boolean values

Boolean

Date Picker

A control that users can use to type or select a date from a calendar view

Date

Date Time Picker

Allows users to enter a date and time value using a calendar view and a time drop-down list

Date, Date Time

Email Address Editor

Allows users to edit an email address Includes validation to ensure that users can only enter valid email addresses.

Email

(continued)

82

Chapter 4 ■ Creating Desktop Applications

Table 4-1.  (continued)

Name

Description

Supported Data Types

Image Editor

Displays an image and allows users to upload an image using a file browser dialog

Image

Phone Number Editor

Allows users to enter a phone number using predefined formats

Phone Number

Web Address Editor

Allows users to enter valid web addresses

Web address, Email

Percent Editor

Allows users to enter valid percentage values

Percent

Money Editor

Allows users to enter a valid monetary value

Money

The image editor control allows users to upload an image. When the user clicks on the control, it shows a Load Image button that opens a file-browser dialog. The date picker control opens a pop-up calendar when the user clicks the control. Users can then use the calendar to select a date. The email and money controls enable data entry and validate the data that’s entered. When users click the phone number control, it reveals a drop-down panel that contains separate data-entry controls for each part that makes up a phone number. The list of permissible formats is specified in the table designer, and you can refer to Chapter 2 to find out more. By default, LightSwitch includes only US formats, so you’ll want to review the phone number formats if you’re building applications for non-US users.

Figure 4-10.  Editable data controls at runtime

83

Chapter 4 ■ Creating Desktop Applications

Displaying Multi-line Text Using the Text Box Control The text box control renders text using a single-line text box. A change you often need to make is to configure a textbox for multi-line data entry, including the entry of line breaks. An example of a field that requires multi-line text is the Description field in the issue table. To configure a text box to accept multi-line text, set the lines property to a value greater than 1 (Figure 4-11).

Figure 4-11.  Enabling multi-line text to be entered

Displaying Data Using Data-Item Containers LightSwitch provides three data-item containers that you can use to lay out data in a pre-formatted fashion. They contain placeholders that are bound to data items on your screen. The data-item containers you can use are the address editor, modal window, and picture and text controls. Figure 4-12 compares the appearance of these controls at both design time and runtime.

84

Chapter 4 ■ Creating Desktop Applications

Figure 4-12.  Data-item containers The address editor contains placeholders that you can assign to any address fields you define in your table. The display name for the control is shown on the address editor label at runtime. When you create a screen with lots of controls, you can hide some of them by using a modal window control. This control displays a button on the screen. When a user clicks this button, LightSwitch opens a modal window popup that includes the controls that exist beneath the modal window control. The picture and text or text and picture controls allow you to display an image and various pieces of associated text.

Using Data-Selection Controls The New Issue screen in our application includes an auto-complete box that enables users to assign an engineer to an issue (Figure 4-13). There are two controls users can use to view or select related entities. These are the auto-complete box and modal window picker controls. Let’s look at these two controls in more detail.

85

Chapter 4 ■ Creating Desktop Applications

Figure 4-13.  Auto-complete box

Using the Auto-Complete Box Control The auto-complete box is a control that’s similar to a drop-down box, in that it allows users to select from a list of drop-down values. However, it’s more powerful than a normal drop-down box because users can type into the control, and the control then filters the items by the text that the user enters. When a user types into the control, LightSwitch searches throughout all records in the underlying table. You can restrict the records that LightSwitch searches by writing your own query and assigning it to the auto-complete box’s choices property. You’ll find out how to create a query in Chapter 5. The Filter Mode property (Figure 4-14) controls the way that the matching works. You can configure the control so that it performs an exact match, or performs a partial match by using the contains operator. You can also configure the case sensitivity of matches, or turn off filtering altogether by choosing the “none” option.

86

Chapter 4 ■ Creating Desktop Applications

Figure 4-14.  Setting the auto-complete box choices and filter mode At runtime, the auto-complete box shows a summary for each row by using a summary control. However, you can show additional properties by changing the summary control to a columns layout and adding the additional properties that you want to display. Figure 4-15 illustrates the appearance of a drop-down row with the phone number property appended to the end.

Figure 4-15.  Setting the items shown in an auto-complete box

Using the Modal Window Picker Control The modal window picker control renders a button on the screen. When the user clicks this button, LightSwitch opens a pop-up window that enables the user to search for and select a record (Figure 4-16).

Figure 4-16.  Modal window picker control at runtime

87

Chapter 4 ■ Creating Desktop Applications

Just like with the auto-complete box, you can configure the fields that appear in the picker by editing the child items of the modal window picker control.

Displaying Static Text and Images With desktop applications, you can easily add static text and images onto your screen. You can use this feature to add screen titles, headers, and company logos to your screen. To add a static item, click the Add button that appears beneath a group control and choose the “Add Image” or “Add Text” options (Figure 4-17).

Figure 4-17.  Addding static text and images

■■Caution  Adding large images can bloat the size of your Silverlight XAP file, slowing down the initial load time of your application.

Setting Control Appearances For each control you add to a screen, you can adjust its size and position through the settings in the sizing section of the Properties sheet. Figure 4-18 shows the properties that you can set—these are similar to the properties you saw in the HTML screen designer.

88

Chapter 4 ■ Creating Desktop Applications

Figure 4-18.  Sizing options Depending on the control you choose, additional sizing options may be available. For example, you’ll find an “Is Resizable” option in some of the layout controls. This allows the user to resize the contents using a splitter control. Figure 4-19 illustrates the effect of checking the “Is Column Resizable” checkbox on the group controls beneath the main columns layout. By checking this option, a splitter control appears between the columns at runtime.

89

Chapter 4 ■ Creating Desktop Applications

Figure 4-19.  Creating resizable screen sections Most of the remaining sizing options are self-explanatory. The width and height settings default to Auto. This means that LightSwitch chooses an optimal width and height based on the space that’s available. If you want to specify a definite size, the units that you can use are pixels or characters and lines. Depending on the control you choose, additional appearance options may also be available.

Positioning Control Labels For each data control you add to your screen, LightSwitch automatically displays a label. If you add a surname text box to your screen, for example, LightSwitch displays a surname label next to the text box. The text that appears in the label comes from the display name value that you define in the table designer. Figure 4-20 shows the Label Position dialog. Again, most of these options are self-explanatory. An interesting pair of options you can choose are None and Collapsed.

90

Chapter 4 ■ Creating Desktop Applications

Figure 4-20.  Label Position dialog If you want to hide a label, you can set the Label Style to None. However, the label still takes up space on the screen, even though it’s not shown. If you choose the “Collapsed” option, the label doesn’t take up any space. This is illustrated in Figure 4-21.

Figure 4-21.  The difference between the “Collapsed” and “None” options

Styling Labels and Static Text Controls In general, you can’t change the fonts that individual LightSwitch controls use. This is because the font settings are designed to be configured using the theme you define for your application. The benefit of a theme is that you can easily maintain a consistent look and feel throughout all screens in your application. A nice feature of the label control is that you can set the font style to one of six predefined styles. Figure 4-22 shows the available font styles and illustrates how they appear at runtime.

91

Chapter 4 ■ Creating Desktop Applications

Figure 4-22.  The available label font styles at design and runtime

Making Controls Read-Only If you want to make parts of your screen read-only, the easiest way to do so is to replace your text boxes with labels. The settings in the Properties sheet for group controls include a “Use Read-only Controls” checkbox. If you set this to true, LightSwitch replaces all child data controls with labels or their read-only equivalents. The other read-only controls that LightSwitch provides are shown in Table 4-2. This table also shows the supported data types.

Table 4-2.  Comparing Read-Only Controls

Name

Description

Supported Data Types

Label

Displays a read-only copy of the data value

All LightSwitch data types

Date Viewer

Displays a date value

Date

Date Time Viewer

Displays a date time value

Date, Date Time

Email Address Viewer

Displays an email address

Email

Image Viewer

Displays an image

Image

Phone Number Viewer

Displays a phone number

Phone Number

Web Link

Displays a web address as a clickable link

Web Address

Percent Viewer

Displays a percentage value

Percent

Money Viewer

Displays a monetary value

Money

92

Chapter 4 ■ Creating Desktop Applications

In Table 4-2, notice how there isn’t a read-only checkbox. If you want to make a checkbox read-only, you need to write code to do so. You’ll see how to do this in Chapter 9.

Including Related Data Items When we created the Add Engineer screen, we chose the checkbox option to include related issue data. By choosing this option, the screen template adds a data grid control that users can utilize to add related issue records to an engineer (Figure 4-23).

Figure 4-23.  Add New Engineer screen with related records If you didn’t select the checkbox item to include related issue records, you can do so afterward by clicking the link that appears in the screen members list (Figure 4-24). LightSwitch shows “Add” links for each table that’s related to the parent table.

Figure 4-24.  Adding related data items to a screen

93

Chapter 4 ■ Creating Desktop Applications

Once the Issues collection appears in the screen members list, you can add a data grid of issues by dragging the Issues collection onto your screen. An important point that might catch you out is that you can only add related data to sections of the screen that are outside the main parent group. For example, you can’t add a data grid of issues to the group that contains the parent engineer data—the option to do that doesn’t appear (Figure 4-25).

Figure 4-25.  Caution: You can only add related data to screen sections outside the main group

Using the Data Grid and Data List Controls There are two controls you can use to display collections of data: the data grid control and the data list control. The main difference between these two controls is that the data list control is designed to show read-only data. The data grid control displays editable data in a grid that contains rows and columns. Users can sort the data in the grid by clicking on the column header. You can add or remove the columns that appear in the data grid by adding or deleting the child nodes beneath the Data Grid node. In contrast, users sort the items in a data list through a drop-down box in the header. By default, it uses a summary control to display each entry in the list. If you want to display additional properties, you can change the summary control to a rows layout and then add your additional fields to that. These two controls are illustrated in Figure 4-26.

94

Chapter 4 ■ Creating Desktop Applications

Figure 4-26.  Differences between the data grid and data list controls

■■Note If you bind a data grid to an attached SQL Server data source, columns that use the text data type cannot be sorted. Use the varchar or nvarchar data types if you want users to be able to sort their data using the column headers.

Creating an Editable Grid Screen The Editable Grid template creates a screen that contains just a data grid. This type of screen is particularly versatile because it provides add, edit, update, and delete features in a single screen. Users find Editable Grid screens really useful because they can quickly work with multiple records and easily compare the data between rows. To create an Editable Grid screen for a table, open the Add Screen dialog, select the Editable Grid template, and select the required table from the drop-down. Figure 4-27 shows the appearance of an Editable Grid screen for the Engineer table at design time. The screen members list shows the Engineer data collection. Unlike the Add New screens, the data source for this screen is a query, rather than a property. Because of this, you can click the Edit Query link to filter the data that appears in the data grid or to apply different sort settings.

95

Chapter 4 ■ Creating Desktop Applications

Figure 4-27.  You can restrict the items shown in the grid by modifying the query Figure 4-28 shows the appearance of this screen at runtime. Notice how the data grid includes a button to export the contents of the grid to Excel. Note also that this button doesn’t appear for browser-based desktop applications.

Figure 4-28.  Editable Grid screen with Excel export option at runtime

Configuring Data Grid Settings If you want to customize the data grid and data list controls, it’s important to understand that these are configured in two places—via the screen query and the properties of the data grid or list. It’s useful to remember where these settings are configured. Otherwise, you could spend a considerable amount of time hunting around the Properties sheet of a data grid trying to find a setting that actually belongs to the query. The screen query represents a data source and is an object of type VisualCollection. Figure 4-29 shows the properties that you can set. These include Auto Execute Query, paging, sort, and search options.

96

Chapter 4 ■ Creating Desktop Applications

Figure 4-29.  Screen query property settings The Auto Execute Query property configures whether or not LightSwitch executes the query when it first opens the screen. To illustrate the purpose of this property, Figure 4-30 shows a hypothetical Data Entry screen that allows engineers to enter timesheet entries. It’s designed as a Data Entry screen that displays only the entries that an engineer enters during a session. When the screen initially loads, you don’t want the data grid to be populated with any previous timesheet entries. You can achieve this behavior by setting the Auto Execute Query property of the timesheet query to false.

Figure 4-30.  Preventing previous records from showing by unchecking the Auto Execute Query option The paging, sorting, and search checkboxes control whether or not LightSwitch shows these options on the data grid. The second place you can configure data grid settings is through the Properties sheet for the data grid (Figure 4-31). The settings here control the visibility of the Export to Excel button, which appears in the data grid toolbar (for desktop applications only), and also control the add-new row behavior.

97

Chapter 4 ■ Creating Desktop Applications

Figure 4-31.  Data grid properties When you uncheck the “Show Add-new Row” checkbox, LightSwitch hides the empty row placeholder that appears at the bottom of the data grid. However, unchecking this doesn’t disable the option to add new records altogether. Users can still add records by clicking on the Add button that appears in the command bar section of the data grid (Figure 4-32). In the next section, I’ll show you how to configure the items on the command bar.

Figure 4-32.  Show Add-new Row property applies only to the grid, not the header

Setting Data Grid Header Buttons If you want to remove the Add button that appears in the command bar or modify the items that appear in this part of the grid, edit the nodes beneath the Command Bar node. You can delete buttons by selecting the button in question and choosing the right-click “delete” option. If you want to add a button to the command bar section, use the Add drop-down that appears beneath the Command Bar node, as shown in Figure 4-33.

98

Chapter 4 ■ Creating Desktop Applications

Figure 4-33.  Editing the data grid command bar buttons This figure shows the command types you can add. Most notably, you can add buttons to allow users to add, edit, or delete the selected record in the grid. The AddAndEditNew and EditSelected buttons open the selected record in an auto-generated dialog (Figure 4-34). One caveat is that the controls in the autogenerated dialog may not look very neat. For example, in Figure 4-34, notice how the auto-generated dialog renders the Problem Description field as a single-line text box when, ideally, a multi-line textbox would be preferable. For this reason, you might want to consider removing the option to edit.

Figure 4-34.  Auto-generated dialog Another command type you can choose from the Add drop-down is the New Button… button. This is particularly useful, because you can use this to write custom .NET code to perform a bespoke task. An interesting set of command types are the DeleteSelected and RemoveSelected items. These two command types sound very similar, but there is a significant difference between the two. The DeleteSelected item marks the selected record for deletion, whereas the RemoveSelected item disassociates the selected record from a parent item. To give an example of how this works, imagine a screen that shows an issue status record and a data grid of issue records that are associated with the issue status record in question. The

99

Chapter 4 ■ Creating Desktop Applications

DeleteSelected command on the data grid would delete the selected issue record, but the RemoveSelected command would disassociate the selected issue record from the issue status record. The actual issue record would still remain in the database.

■■Note The auto-generated dialog doesn’t look very neat. Therefore, in Chapter 9 I’ll show you how to customize the window that’s shown to the user.

Creating a List and Details Screen The List and Details Screen template creates a screen that shows a list of items on the left part of the screen and the details for the selected item on the right. The screen that this template generates provides a great example of how LightSwitch keeps track of the selected data item whenever you work with collections of data. To create a List and Details screen for the Engineer table, open the Add Screen dialog, select the List and Details Screen template, and select the Engineer table from the Screen Data drop-down. Figure 4-35 shows the view that you should see in the screen designer.

Figure 4-35.  List and Details screen in design view The screen this template creates includes a list control that binds to the Engineers collection. In the screen member list, you’ll find a node beneath the Engineers collection that’s labeled ”Selected Item.” The controls in the details section of the screen bind to the properties of the selected item. So, at runtime, when a user changes the selected item by selecting an engineer from the list control, the detail controls automatically refresh themselves to reflect the selected record (Figure 4-36).

100

Chapter 4 ■ Creating Desktop Applications

Figure 4-36.  Runtime view of List/Details screen

Creating a Search Screen The Search Screen template creates a screen with simple search functionality. To create this type of screen, open the Add Screen dialog, select the Search Data Screen template, and select a table or query from the drop-down. Figure 4-37 illustrates a screen that’s based on the Search template. The key feature of this template is that it includes a search text box. At runtime, a link appears against each search result item. This link opens the selected record in a Details screen, but if you haven’t created a details screen, LightSwitch opens the record in an auto-generated screen.

101

Chapter 4 ■ Creating Desktop Applications

Figure 4-37.  The Search screen shows records that contain the search criteria The search operation matches all records that contain the search criteria (as opposed to an exact match, or a “begins with” match). This operation searches throughout all string fields in the underlying table where the Is Searchable property is set to true. Behind the scenes, LightSwitch uses the Search operator, which is exposed via the IDataServiceQueryable query property of the screen’s data source. In the current version of LightSwitch, you can’t configure the matching technique that the search feature applies. For instance, if you want to return all records that begin with the criteria value that the user enters, you need to create a custom Search screen. The search feature only matches against the string properties of an entity. It won’t match the search criteria against numeric properties or navigation properties.

Creating Details Screens Details screens are designed to show individual, existing records. Unlike the screens you’ve seen so far, Details screens are launched from other screens and can’t be opened directly. As I mentioned in the previous section, one way a user can open a Details screen is through the results grid of a Search screen. Through the table designer (in the client perspective), you can define the default Details screen for each table. Your application uses the screen you define here whenever it needs to open a record of that particular type. The absence of a Details screen for any given table doesn’t prevent LightSwitch from displaying data. If a default screen doesn’t exist, LightSwitch displays the data using an auto-generated screen. However, the auto-generated screens can’t be customized in any way (just as with the auto-generated screens in the data grid) and may not render data in the most presentable fashion (Figure 4-38). Therefore, the advantage of using a custom Details screen is that you can better customize the appearance of your screen.

102

Chapter 4 ■ Creating Desktop Applications

Figure 4-38.  Here’s an auto-generated screen—it’s functional but not pretty

Walkthrough 4-2. Using Details Screens To demonstrate how to build and use Details screens, this walkthrough will show you how to construct a Details screen that shows the issues that are assigned to an engineer. The next part of the walkthrough will configure the Engineer Search screen so that it opens the Details screen. Figure 4-39 shows the end result of this walkthrough. Each result in the Search screen will contain two links. The first link opens the Details screen for the engineer, and the second link opens a Details screen that shows the issues that are assigned to the engineer.

103

Chapter 4 ■ Creating Desktop Applications

Figure 4-39.  The Search screen at runtime

Building Details Screens The first part of this walkthrough is to create a set of Details screens: the first to show the engineer details, and the second to show the issues that are assigned to a specific engineer. Here are the steps to carry out: 1. Create a Details screen for an engineer record. To do this, open the Add Screen dialog, select the Details Screen template, and select the Engineer table from the drop-down. Keep the default name of EngineerDetail and click the OK button. 2. Create a Details screen that shows the issues for an engineer. To do this, create a second Details screen based on the Engineer table. Make sure to select the “Engineer Issues” checkbox in the “additional data to include” section while you’re in the Add Screen dialog. Name your screen EngineerIssues. 3. Configure your EngineerIssues screen so that it only shows issue data. To do this, open the screen designer and delete the engineer details so that only the Issues Data Grid remains (Figure 4-40).

104

Chapter 4 ■ Creating Desktop Applications

Figure 4-40.  EngineerIssues Screen

Launching Details Screens Now that you’ve added Details screens to your application, the next step of this walkthrough is to configure the Search screen so that it opens the two Details screens. The key to launching Details screens is to set up labels so that they display as a link, and to specify the name of the Details screen that you want to use. To modify your Search screen so that it launches the Details screens, do the following: 1. Open your Engineer Search screen in the designer. Select the surname label, open the Properties sheet, and go to the appearance section. This section contains a “Show as link” checkbox and includes a Target Screen drop-down. Make sure that the Target Screen setting is set to your EngineerDetail screen. 2. Create a second link that opens the Engineer Issues screen. To do this, open the Properties sheet for the IssueCount label. Check the “Show as Link” checkbox and choose EngineerIssues from the Target screen drop-down (Figure 4-41). By doing this, each issue count cell in the search grid will be rendered as a link. When the user clicks on this link, LightSwitch will open the record using the EngineerIssues screen.

105

Chapter 4 ■ Creating Desktop Applications

Figure 4-41.  Setting a Target screen This completes the configuration of the grid, and you can now run your application. The technique that’s shown in this walkthrough can help you improve the overall navigation of your application.

Setting Application Properties The Properties sheet of your client project (Figure 4-42) allows you to control application-level settings. It enables you to change the shell and theme of your application. As I explained in Chapter 1, changing the shell and theme alters the look and feel of your application.

Figure 4-42.  General Properties pane

106

Chapter 4 ■ Creating Desktop Applications

You can also set your application name in the General Properties pane. LightSwitch shows the text that you enter here in the title bar of your application. In a desktop application, LightSwitch shows the server name in the title bar after the application name. This is a security feature that Silverlight imposes, and it isn’t possible to hide the server name. The Icon settings allow you to assign icons to your application by selecting a PNG file with an ideal size of 32x32 pixels. LightSwitch displays icons depending on the application type and the shell that you choose. For example, if you choose the Cosmopolitan Shell, your logo image will appear in the banner of your application. In a desktop application that uses the Standard Shell, the application icon appears in the title bar of your application, while the logo image appears in the desktop shortcut that starts your application.

Configuring Screen Navigation The navigation menu enables users to open the screens in your application. For applications that use the Standard Shell, this menu appears along the left-hand side of your application. If you choose to use the Cosmopolitan Shell, the menu appears across the top-most section of the window. The Screen Navigation tab allows you to manage the items that appear in the navigation menu. In particular, you can create groups to help better organize your screens. Figure 4-43 shows the Screen Navigation tab in the designer, alongside the corresponding menu in the running application.

Figure 4-43.  Screen navigation at design time and runtime LightSwitch automatically adds any new screen that you create to the navigation menu. This, however, excludes any screens that are based on the Details Screen template. You can add multiple menu items that refer to the same screen. If you want to prevent users from opening a specific screen, right-click the screen and select “Delete.” The Include Screen drop-down allows you to add two built-in screens called Users and Roles. These screens allow you to manage the security of your application. By default, these screens are added into the Administration group.

107

Chapter 4 ■ Creating Desktop Applications

At debug time, the Administration group isn’t shown. This group only appears in deployed applications and is only shown to application administrators. LightSwitch recognizes the permissions of the logged-on user when it builds the navigation menu at runtime. If a user doesn’t have sufficient permission to access a screen, LightSwitch doesn’t show it in the navigation menu (Chapter 22 shows you how to set screen-level permissions). This makes life really easy, because you don’t need to do any extra work to configure menu-item permissions. Finally, you can set the initial screen that’s shown to your users by specifying the start-up screen. But if you don’t want any screens to be shown at start-up, you can use the Clear button to unset your start-up screen.

Designing Screens at Runtime It’s difficult to visualize how a screen might look at runtime when you’re designing it through a series of tree nodes. To simplify this task, LightSwitch provides a runtime designer you can use to design screens at debug time. This is particularly useful when you want to configure the size and appearance of controls, because it allows you to see immediately the changes that you’re making. To use the runtime designer, start up your application (press F5) and click on the Design Screen link or button (depending on the shell that you’ve chosen). This opens the runtime designer, as shown in Figure 4-44.

Figure 4-44.  Runtime screen designer The runtime designer enables you to add and delete controls and to change the appearance properties of the controls on your screen. You can even add and delete group controls. Although the runtime designer provides a great way to visually design your screens, it has some slight limitations. You can’t add new data items such as local screen property queries or methods. Also, you can’t move items out of their layout containers or modify the underlying VB or C# code on your screen.

108

Chapter 4 ■ Creating Desktop Applications

One last caveat—when you deploy your application, don’t forget to change your build configuration from Debug to Release. If you forget, the link to runtime designer will appear in your deployed application.

■■Tip  If you spend most of your time in Visual Studio, it’s easy to overlook the runtime screen designer. The top tip for this chapter is to remember the runtime designer. It definitely makes screen design much easier.

Reducing Project Sizes Earlier versions of LightSwitch suffered from a problem. The minimum size of each LightSwitch project was around 180 MB. This large project size made it very difficult to back up, share, or email your LightSwitch projects. Thankfully, this situation is now much improved. A simple project in LightSwitch takes no more than around 50 MB. But if you need to reduce your project size for archiving or sharing purposes, delete the files in the .DesktopClient\bin and .Server\bin folders. LightSwitch recreates these files when you next compile your application, so there’s no need to worry about permanently damaging your project. By deleting these files, you can compress a simple LightSwitch project down to around 15 MB. But, if you do start deleting files, make sure not to delete the files in the bin\data folder, because this is the place where LightSwitch stores the Intrinsic database.

Summary This chapter showed you how to build rich desktop applications. Compared to HTML client applications, you can do more with desktop applications. For example, you can better integrate with Office applications, take advantage of richer controls (such as grids), and write your application entirely in .NET code. The principles of desktop screen design are the same as those for HTML client screen design. You create screens with templates and use a tree view–based interface to design your screens. Once in the designer, you can lay out your screen with group controls and use data controls to allow users to view and edit data. The screen template types you can use include Details, New Data, Search, Editable Grid, and List/Details. New Data screens enable users to create records one at a time. Details screens show a single record and can optionally display related data. Details screens must be opened from other screens and cannot be opened directly. The other screen template types build screens to display multiple records. To organize the layout of your screens, the group controls you can use include Rows, Columns, Tabs, Table, and Group Box. Controls that display scalar data include textbox, label, checkbox, and a whole range of other controls that are tailored for business types. If you want a control that allows users to select a record, you can use either an auto-complete box or a modal window picker. To display lists of related records, you can use either the data grid or data list controls. The difference between these two controls is that the data list control is designed to show data in read-only mode. Unlike with the HTML client, you can easily add static text to your screen by right-clicking a group control and selecting the “Add Text” option. When you add a label onto your screen, you can show the label as a link and set a target screen. This enables a user to launch a related child screen by clicking on the link. All controls have appearance properties you can set, such as the height and width. It’s easiest to set these properties when you’re using the runtime designer, because you can see immediately the changes that you’re making. Finally, you can configure application-level settings through the General Properties window. You can use the settings you find here to configure your application’s title, icon, and screen navigation menu items.

109

Part II

Working with Data

Chapter 5

Quer ying Your Data Queries are a fundamental part of all applications. By using queries to filter data, you can build screens that display a subset of records, or configure controls to show targeted pieces of information. In this chapter, you’ll learn the following: •

how data retrieval works and what happens at the server during query execution



how to filter and sort data by using the graphical designer



how to practically apply queries to your application

LightSwitch provides a designer that you can use to graphically build a query. To keep things simple, this chapter will focus only on the graphical designer. Later in this book, I’ll show you how to build more-complex filter expressions through code. To illustrate practical examples of how to use queries in your application, the final part of this chapter will show you how to limit the engineer names that are shown in the data picker controls as well as how to build a screen that shows only the help-desk issues that are overdue.

Introduction to Data Retrieval I’ll begin this chapter by explaining the data-retrieval process and describing what happens at the server when LightSwitch executes a query (the Query pipeline process). From a technical perspective, every data source in your application has a corresponding data service that runs on the server. When you build a query in the graphical designer, LightSwitch creates a Query operation at the data service. It exposes this Query operation as an OData service endpoint. When a user wishes to retrieve some data, the LightSwitch client calls the Query operation method via an OData call. If you define parameters on your query, the client will supply the necessary arguments. When the server completes the query, the Query operation returns either single or multiple entities to the client.

LightSwitch Queries Always Return Entities Because query operations return entities from an entity set, the shape of the query results cannot be modified. For example, a query could return a single engineer, or a collection of engineers. Alternatively, it could return a single issue, or a collection of issues. However, a query can’t return just the first name from a set of engineers, nor can it return some sort of combined object that’s created by joining engineers and issues. This behavior may seem strange, particularly for Access or SQL developers who are accustomed to selecting just the columns they need or returning results that are joined to other tables.

113

Chapter 5 ■ Quer ying Your Data

At this point, you might wonder how to retrieve additional data that isn’t part of the underlying data set. Provided that you’ve set up correct relationships between entities, you can retrieve related data by using the navigation properties that you’ve defined. Once you start thinking in the LightSwitch way, you’ll soon realize that it isn’t necessary to return joined data from queries.

Understanding the Query Pipeline When you call a query in LightSwitch, the server-side execution passes through the Query pipeline. The Query pipeline consists of phases that include points where you can inject your own custom server-side code. Figure 5-1 shows the phases in the Query pipeline and highlights the points where you can add custom code.

Figure 5-1.  Query pipeline At the start of the Query pipeline, the CanExecute method allows you to carry out security checks and to apply access-control rules. You can find more about writing authorization code in Chapter 22. You can apply complex filters and sort conditions by writing LINQ code in the PreProcessQuery method—you’ll see plenty of examples of how to do this later in the book. During the Execution phase, LightSwitch transforms the query into one that the data provider understands (examples of data providers are the ADO.NET Entity Framework provider for SQL Server, or the OData data provider for SharePoint). During the Execution phase, LightSwitch also translates business types between their underlying storage type and business-type representation. If the query succeeds, the Query pipeline executes any custom code that exists in the Executed method. For example, you could write custom code here to audit the users who have viewed the data. If the query fails, you can perform additional error handling by writing code in the ExecuteFailed method.

114

Chapter 5 ■ Quer ying Your Data

■■Tip If your query fails to return data, handle the ExecuteFailed event and place a breakpoint in the method. Once you do this, you can use the debugger to see the details of the full exception by examining the queryDescriptor object.

Using LightSwitch’s Default Queries LightSwitch automatically generates two queries called All and Single for each entity set in your application. Taking the engineers example, LightSwitch generates a query called Engineers_All that returns all engineers, and a query called Engineers_Single that returns a single engineer by ID value. These default queries are important, because you can use them in several ways. If you create an Editable Grid screen and select Engineers from the screen data drop-down, LightSwitch uses the Engineers_All query as the data source. If you create a Detail screen for an engineer, LightSwitch uses the Engineer_Single query as the data source. Another place where you’ll see default queries is if you add additional data items to a screen by clicking the Add Data Item button in the screen designer, as shown in Figure 5-2.

Figure 5-2.  Adding default queries to your screen If you create a query by right clicking the Engineer table in Solution Explorer and choosing the “Add Query” menu item, LightSwitch bases your query on the Engineers_All query.

115

Chapter 5 ■ Quer ying Your Data

Theoretically, this reveals two important principles about queries. The first is that queries that return collections are composable. This means that you can create queries that are based on other queries. The second principle is that the _ALL query will always be the base query for any user query that you define.

Filtering and Sorting data LightSwitch provides a clean and simple tool with which you can build queries: the graphical query designer. This allows you to sort and filter data in several different ways. For example, you can filter by hard-coded values, other property values, or by global values. This section will describe all of these options in greater detail.

Creating Queries Based on Entities To create a user-defined query, right click a table in Solution Explorer and choose the “Add Query” menu option. Because queries are composable, you can extend existing queries by selecting the right-click “Add Query” item for the query. When you create a query, you can use the properties sheet to set various attributes (Figure 5-3). Let’s look at some of these settings in more detail.

Figure 5-3.  Query properties

116



Name – This value uniquely identifies your query in Solution Explorer and appears in the screen data drop-down box that’s visible in the Add New Screen dialog.



Number of Results returned – This displays a drop-down box with the options “One” or “Many.”

Chapter 5 ■ Quer ying Your Data



Description – You can use the description to add a comment about your query at design time. The description text isn’t exposed elsewhere in LightSwitch during design time or runtime.



Display name – This specifies a friendly name and appears in the query source drop-down in the screen designer (Figure 5-4)

Figure 5-4.  Query display name shown on a screen By default, any new query that you create returns multiple records. The Number of Results setting controls this behavior. Selecting the “one” option from this drop-down defines the query as a singleton query. This is a query that returns either a single record or null. Singleton queries are not composable and can’t be further modified. If you designate a query as a singleton query and create a query that returns more than one record, LightSwitch will not generate a compile-time error. Instead, it will throw an exception at runtime when the query executes. The Number of Results Returned option also specifies where the query appears in the Add New Screen dialog. You can use singleton queries to create New Data and Detail screens in desktop applications, or View Details and Add/Edit Details screens in HTML applications. In desktop applications, you can use queries that return multiple records to build Editable Grid, List and Details, and Search Data screens. And in HTML applications, you can use queries that return multiple records to build screens with the Common Screen Set and Browse Data Screen templates.

Applying Filters Once you add a query, you can use the graphical designer to filter your data. Figure 5-5 illustrates the controls that you can use to set up filters.

117

Chapter 5 ■ Quer ying Your Data

Figure 5-5.  The parts that make up a filter The operator drop-down defines the operator that you want to apply. Some of these operators will depend on the data type of the selection property and whether the property is defined as a required property. The comparison type drop-down allows you to choose from the options literal, property, parameter, or global. The literal option creates a filter that uses a hard-coded value. For example, Figure 5-6 illustrates how to create a query that returns issues that are assigned to a specific engineer. Because engineer details are held in a separate table, this screenshot illustrates how you can use the AssignedEngineer navigation property to filter by related parent records.

118

Chapter 5 ■ Quer ying Your Data

Figure 5-6.  Creating filters using literal values When you apply multiple filter conditions to a query, you can parenthesize your conditions by adding filter groups (Figure 5-7). The operators you can apply between groups are “And,” “Or,” “And Not,” and “Or Not.”

Figure 5-7.  Applying filter groups

Comparing Against Other Fields/Properties The comparison type drop-down enables you to create a filter that compares by property. This allows you to compare two fields from the same record. After choosing the property option, LightSwitch displays a second drop-down box you can use to specify the comparison property. Figure 5-8 illustrates a query that returns issues that have overrun by filtering on issues where the close date exceeds the target end date.

Figure 5-8.  Comparing against another property

119

Chapter 5 ■ Quer ying Your Data

Passing Arguments into a Query Rather than use hard-coded literal values, you can make queries more reusable by creating parameters. To create a parameter, choose the parameter option from the comparison type drop-down menu. After you select the parameter option, a second drop-down box appears that prompts you to either create a new parameter or to select an existing parameter (if one exists). If you choose to create a new parameter, the parameter appears in the parameter section in the lower section of the query designer. You can make parameters optional by checking the “Is Optional” checkbox. If the user doesn’t set the value of an optional parameter at runtime, LightSwitch won’t apply the filters that use that parameter. Optional parameters are ideal for creating search queries that filter on multiple fields. If the user doesn’t enter search criteria for any given field, LightSwitch simply omits the filter clause. The outcome is that LightSwitch can execute the query more quickly and efficiently.

Filtering by Global Values When you create filters on date or person properties, you can filter by a range of dynamic values that are known as global values. If you filter by a date property, you can choose from a set of global values that includes Today, Start of Week, End of Week, and several others (Figure 5-9).

Figure 5-9.  Global value options when filtering by Date/DateTime If you filter on a DateTime property, take care when you apply the equals operator with the Today global value. For example, the Issue table contains a field called ClosedDateTime. If you want to create a query that returns all queries that are closed today, the filter ClosedDateTime=Today won’t work as you’d expect. This is because Today returns today’s date with a time element of 12:00:00am. So, to apply the correct filter, you have to use the “is between” operator and filter the ClosedDateTime property between Today and End of Day. Therefore, Start of Day is perhaps a better description for the value that’s returned by the Today global value. For Person type properties, LightSwitch provides the global values Current User and Anonymous User. You can see this by creating a query and adding a filter that filters by the built-in CreatedBy property (Figure 5-10). A practical use of this feature is to build screens that show only the records that were created by the current logged-on user.

120

Chapter 5 ■ Quer ying Your Data

Figure 5-10.  Global values for Person properties

Modifying Screen Queries When you create a screen that’s based on a collection of data (an Editable Grid screen in a desktop application or a Browse screen in an HTML client application), you can define additional parameters, filtering, and ordering at the screen level. To do this, click on the Edit Query link that appears next to your data collection (Figure 5-11). This opens the graphical query designer and enables you to apply filter and sort conditions.

Figure 5-11.  Editing a screen query Compared to creating a custom query, a benefit of modifying the screen query is that it keeps the logic contained within the screen and saves you from cluttering up your view in Solution Explorer with lots of one-off queries. However, a disadvantage of this approach is that filter conditions are applied only to the screen and cannot be reused on other screens. It’s also not possible to customize this type of query further by writing code.

Sorting Data You can use the graphical query designer to sort the output of your query by multiple properties (Figure 5-12). Any control you bind to a sorted query will display data in the sort sequence that you define.

121

Chapter 5 ■ Quer ying Your Data

Figure 5-12.  Sorting a query by multiple properties The first drop-down allows you to select a property. The second drop-down allows you choose from the sort sequences Ascending and Descending. After you specify a sort condition, you can sort on additional properties by clicking on the Add Sort button. You can sort queries by related parent properties. In Figure 5-12, notice how you can sort issues by the related engineer’s surname. However, it isn’t possible to sort queries by related child records. To illustrate this in the context of the Help Desk application, users and engineers can add multiple issue-response records to each issue. It isn’t possible to create a query on the Issue table that sorts the output using the response date that’s held in the issue response table (this would allow you to return the issues that have most recently been worked on). To perform this type of sort, you need to extend your query by writing code in the PreProcessQuery method, which I will cover later in this book.

Sorting Data Grids in Desktop Applications In desktop applications, users can toggle the sort order of the data in a grid by clicking on the column headings. The column header includes an arrow that indicates the sort order that’s currently in use (shown in Figure 5-13).

Figure 5-13.  Sorting a query LightSwitch retains the sort sequence between sessions, and even retains the sort sequence after the user closes and reopens your application. The problem with this behavior is that it isn’t possible for a user to clear the grid sort order and return to the initial sort sequence that you intended. To give an example, let’s suppose you create an Editable Engineer Grid screen that uses a query that sorts the data by surname followed by first name. If the user opens this screen and sorts the data by priority, there isn’t any way for the user to return to the initial sort sequence of surname followed by first name.

122

Chapter 5 ■ Quer ying Your Data

Therefore, if you create Grid screens that use queries that are sorted by multiple properties, it makes sense to disable sorting to prevent this problem from occurring. To do this, uncheck the “Support Sorting” checkbox for your query in the screen designer.

■■Note The controls in the HTML client application include no built-in way for users to sort the data that’s shown on the screen. By using queries, you can add sort capabilities to your HTML client application.

Examining User-Setting Files To explain the grid sort behavior for desktop applications, LightSwitch retains the user settings for your application in the following path, which appears below your Documents folder (or My Documents on Windows XP machines): Microsoft\LightSwitch\Settings\ This folder contains a subfolder for every LightSwitch application that you’ve run on your computer. Inside each application folder, you’ll find a .SortSettings file for each screen in your application (Figure 5-14). This is an XML file that contains the user sort orders for the screen. Users can clear their sort settings by manually deleting this file.

Figure 5-14.  File listing of C:\Users\Tim\Documents\Microsoft\LightSwitch\Settings\HelpDesk.1.0.0.0 In this folder, you’ll find various other files. If a user resizes the widths of the columns on a data grid, LightSwitch persists these settings between sessions in the .ColumnSettings file. LightSwitch uses the remaining files to retain the state of the application, navigation, and ribbon settings. Listing 5-1 shows you the contents of the Application.OutOfBrowser.WindowSettings file. LightSwitch uses the data in this file to reopen your application in the same screen position as your last session. Listing 5-1.  Contents of Application.OutOfBrowser.WindowSettings

123

Chapter 5 ■ Quer ying Your Data

Walkthrough: Working with Queries To demonstrate the topics in this chapter, the following walkthrough describes practical examples of how to apply queries in the Help Desk application. To begin, I’ll show you how to limit the engineer names that are shown in the data picker controls, and then I’ll show you how to build a screen that displays help-desk issues that are overdue.

5-1. Filtering Controls Here’s a typical scenario that occurs when you work with employee data. In the context of the Help Desk application, issues are assigned to engineers. When an engineer leaves the company, the engineer record must still remain in the database for historical purposes. But when a user creates a new issue record in the application, it shouldn’t be possible to assign an ex-exployee to a new issue. To support this functionality, the Engineer table includes a Boolean field called active. Managers of the Help Desk application can therefore mark ex-employees by disabling the active flag. Figure 5-15 shows a screenshot that highlights how the application looks when complete.

Figure 5-15.  Final outcome of this walkthrough The screenshots in this section are based on an HTML client application, but the steps are identical for a desktop application. As a prerequisite, you need to add an Add/Edit Details screen (HTML client), or a New Data screen (desktop client) for the Issue table. Here are the steps to carry out: 1. In Solution Explorer, right click the Engineer table and select the “Add Query” menu item. 2. Click the Add Filter button and add a filter that filters the active property by the literal value True (Figure 5-16). Name your query ActiveEmployees.

124

Chapter 5 ■ Quer ying Your Data

Figure 5-16.  Create a query and filter the Active property to True 3. In your client project, open the Issue Data Entry screen you want to use. Click the Add Data Item button and add the ActiveEngineers query to your screen (Figure 5-17). This step is necessary in order to make the query visible on your screen.

Figure 5-17.  Use the Add Data Item dialog to add the query to your screen 4. In the screen designer, select the assigned engineer control. In the case of an HTML client application, this would be a details picker control, whereas for a desktop application, it would be an auto-complete box control. Here’s the key step. Open the properties sheet for your control and set the Choices property to the ActiveEngineers query (Figure 5-18).

125

Chapter 5 ■ Quer ying Your Data

Figure 5-18.  Configure your control to use the ActiveEngineers query You can now run your application. When you open your Issue Data Entry screen, you’ll be able to assign only active engineers to the issue record.

5-2. Using Queries on Screens This second walkthrough will show how to create a screen that displays all issue records that are overdue. This demonstrates a typical screen in an application to help users focus on specific records, or to carry out a particular piece of workflow.

Figure 5-19.  Outcome of this walkthrough—A view of all overdue issues

126

Chapter 5 ■ Quer ying Your Data

Here are the steps to complete this walkthrough. Just like the previous walkthrough, these steps are appropriate for both HTML and desktop client applications. 1. Create a new screen for your application that’s based on the Issue table. For an HTML client application, choose the Browse Data Screen template, whereas for the desktop client, choose the Editable Grid Screen template. Name your screen Overdue Issues. 2. Modify the screen query to return the relevant records. To do this, click the Edit Query link that appears next to the Issues collection in the Screen Member List. When the query designer opens, create a new filter on the TargetEndDate property. Set the Operator to “ Id property against an optional parameter.

Creating the Search Screen The next step is to build a screen that’s based on your search query. In the case of an HTML client application, create a new screen based on the Browse Data Screen template. For desktop clients, choose the Editable Grid Screen template. In both cases, set the data source of your screen to the search query that you created—in this example, the IssueSearch query. At this point, the screen designer will look similar to the screenshot that’s shown in Figure 10-4. When the screen template creates your screen, it detects that your query includes parameters. Because of this, it automatically adds data-entry controls to enable users to enter search criteria values. As you would expect, the screen template binds these data-entry controls to local properties and maps the query parameters to these properties.

307

Chapter 10 ■ Searching Data

Figure 10-4.  LightSwitch creates local properties that bind to the query parameters Note that for HTML client applications, the screen template generates read-only data-entry controls. You therefore need to change these to editable controls to enable users to enter the search criteria values. In this example, you’ll need to change the control for the target end date properties to Date/Time pickers and change the control for the problem description to a textbox control. You can also set the control for the assigned engineer ID to a modal picker control. By doing so, users will be able to select an engineer by name, rather than by numeric ID. For desktop client applications, the screen template creates a screen that includes editable controls for the entry of the search criteria values. It sets the assigned engineer ID property to use an auto-complete box, which will enable the user to select an engineer by name during runtime. At this point, you can run your application. When you open your search screen, you’ll be able to use the controls to filter the data that the screen shows. The important part of this walkthrough is that it highlights the key role that the underlying query plays in terms of developing a custom Search screen. In the remainder of this chapter, I’ll focus on techniques you can use to further refine this underlying query.

Building Advanced Searches Up until now, the queries I’ve showed you have all been built with the graphical screen designer. The graphical designer can only take you so far. If you want to develop more sophisticated search routines, you need to understand how to apply query filter conditions with LINQ code. In this section, I’ll introduce the theory of how LINQ works and then follow this up by showing you examples of how to use LINQ code in your applications.

Introducing LINQ LINQ is the .NET framework component that provides querying capabilities. With LightSwitch, there are two main places where you can utilize LINQ code. The first is in Silverlight desktop applications. Here, you can write screen code to access and filter data. The second is in server-side queries. Here, you can extend your queries to include filter operations that you can’t perform with the graphical designer. This is where the focus of this chapter lies.

308

Chapter 10 ■ Searching Data

With LINQ, you can express queries using two different types of syntax: Query Syntax and Method (or Lambda) Syntax. Let’s take a look at these two different flavors of LINQ.

Understanding Query Syntax Code You commonly find Query Syntax used in documentation, and the key characteristic of this syntax is that it’s quite readable. The syntax itself looks a bit like SQL. Figure 10-5 shows a snippet of Query Syntax code. This figure highlights valid code you can add to an Engineer Details screen on a desktop application. This code returns a collection of open issues that are associated with an engineer, sorted in date-descending order. The purpose of this figure is to summarize the parts that make up a query.

Figure 10-5.  Parts that make up a query expressed using Query Syntax Let’s take a closer look at this syntax. Every query needs a data source, and in this sample, the Engineer.Issues navigation property is the data source. Because the code belongs to a Detail screen, Engineer refers to the Engineer query that the Detail screen template generates. The engIssue variable is called the range variable. This behaves just like the iteration variable in a for-each loop, although no actual iteration takes place in a LINQ query. You can use this variable to refer to each element in the data source, which enables you to conditionally filter the results by using a where clause. The compiler infers the data type of engIssue, and because of this there’s no need for you to explicitly declare this as an Issue object. The select clause at the end of the statement specifies the type of each returned element. This allows you to return only a subset of properties from the Issue entity, if required. A very important characteristic of LINQ you should be aware of is deferred execution. This means that the application executes the query at the point at which it requires the data, and not on the line that contains the select clause. If you define a LINQ query and don’t use the results, your application will not execute the query.

Understanding Method (Lambda) Syntax Code Although Query Syntax is generally easier to read and write, there are certain operations that you can perform only with Method Syntax. Retrieving the element with the maximum value in a source sequence is one example.

309

Chapter 10 ■ Searching Data

Method Syntax queries are characterized by lambda expressions, such as the one shown in Figure 10-6.

Figure 10-6.  Parts that make up a query expressed using Method Syntax This figure illustrates the same query as before, but expressed using Method Syntax rather than Query Syntax. The where method, which is shown in this illustration, is an example of a Standard Query Operator. Standard Query Operators are extension methods on top of objects that implement the IEnumerable or IDataServiceQueryable interface. You can use Standard Query Operators to carry out useful tasks against collections of data, such as filtering or ordering. In many cases (as with the example shown in Figure 10-6), you can control the way that many of these Standard Query Operators work by supplying a lambda expression. The Standard Query Operators you can apply in a LINQ query depend on the data source that you choose. For this example, where the data source is a navigation property, there are over fifty Standard Query Operators you could apply. In addition to the where and orderby operators, there are many other useful operators that you can use. For example, there are various aggregate operators, which include count, min, max, and average. When the data source is a navigation property, any additional operators you apply will apply locally in memory. However, if you compose a remote query against the actual OData service, the set of operators you can use is limited to the set that OData supports.

Filtering Data with Lambda Expressions To explain how lambda expressions work, let’s take a closer look at the where operator and lambda expression from Figure 10-6:

310

Chapter 10 ■ Searching Data

The where operator requires you to supply a Func delegate that returns a Boolean. The return value indicates whether the object you supply (engIssue) meets the criteria for inclusion in the where clause. engIssue is called the lambda parameter. This represents a single issue in the collection of issue responses that you’re working against. This code uses .NET’s implicit data-typing feature, which saves you from having to define the data type of engIssue. You could equally write the expression like this:

If you want to construct more-complex query expressions, you can do so by using the navigation properties that your lambda parameter exposes. In the C# version, the lambda parameter must be enclosed in brackets if you don’t use implicit typing. You must also use brackets if you specify more than one lambda parameter. In C#, the => operator is called the lambda or goes to operator. This separates the lambda parameter(s) from the actual expression. In VB, the Function keyword specifies the lambda expression, and the lambda parameters are defined inside brackets following the Function keyword. VB developers may find it strange to see the Function keyword used without a function name being specified. For example, a typical function in VB looks like this. Public Function GetIssue (issueId

As Integer) As Issue

As you can see, the function name here is called GetIssue. In the lambda expression code, you can omit the function name, because the syntax uses a feature of .NET 3.5 called anonymous methods. Prior to .NET 3.5, methods had to be explicitly named, which would have resulted in your having to write more code. The final part of the lambda expression tests to see if the ClosedDateTime value is null. If true, the query returns the record in the results.

Practical Querying Examples Now that you understand the basic theory of how LINQ works, this section will describe several query techniques you can use in your application. The code samples in this section apply additional filter conditions by adding code to the PreprocessQuery method of a server query.

Filtering by Related Child Items In the walkthrough at the start of this chapter, I showed you how to use the graphical designer to filter issue records by the assigned engineer property (assigned engineer is a related property). Working in the other direction, however, you can’t filter a query on the engineer table by a property in the issue table. Figure 10-7 illustrates this limitation by showing how the drop-down box in an engineer query doesn’t contain an entry for the Issue navigation property.

311

Chapter 10 ■ Searching Data

Figure 10-7.  You cannot filter by child items in the graphical designer Fortunately, you can overcome this restriction by writing LINQ code. To demonstrate how to do this, I’ll show you how to build a query to return engineer records that are assigned to issues that are overdue. The process to extend a server query with LINQ involves writing code in the PreprocessQuery method of a server-side query. The PreprocessQuery method defines code that LightSwitch executes before it submits your query to the underlying data store. This is a common technique, which you’ll apply to the rest of the examples throughout this chapter. To create this example, right-click the engineer table and create a query called EngineersWithOutstandingIssues. Click the Write Code button and select the PreprocessQuery method. When the code editor opens, enter the code that’s shown in Listing 10-1. Once you create this query, you can create a Browse screen based on it to view the output. Listing 10-1.  Filtering by child items

312

Chapter 10 ■ Searching Data

In the code that’s shown here, the PreprocessQuery method includes a parameter called query that defines the query’s output. So, to customize your query further, you would need to apply additional LINQ query operators to this parameter. The first part of this code applies the where operator on the set of engineer records. For each specific record, if the condition inside the where operator resolves to true, the query will return the specific record in the final output. engItem is the range variable. This variable allows you to reference individual engineer properties in the query data source. This code applies a second where operator on the issues navigation property of the engItem variable. This call returns issue records that are associated with the engineer where the issue status description matches the value “open.” The code then applies the Any operator on this result. The Any operator returns true if one or more issue records match the “open” condition. If this call returns true, the query will include the engineer record in the final output. Once you complete and save this query, you can build a screen that uses this query, just like the custom Search screen example.

Exists, In Exists or in type queries are useful because they help you find records where related child records exist. To illustrate this type of query, the following sample shows you how to return engineers who are associated with one or more records in the issue table. In traditional order-processing systems, this is the type of query you would use to identify customers with orders. If you’re more conversant with SQL, Listing 10-2 provides the SQL translation to illustrate what this example strives to achieve. Listing 10-2.  SQL equivalent of Exists query

313

Chapter 10 ■ Searching Data

To recreate this example, create a query called EngineersWithIssues. Click on the Write Code button, select the PreprocessQuery method, and enter the code shown in Listing 10-3. Listing 10-3.  Returning all engineer records with related issue records

This code is similar to the previous example. It uses the where standard operator and applies the Any operator on the Issues navigation property to determine whether the query should include the engineer record in the final query output.

Not Exists, Not In As a natural progression of the previous example, here´s how to perform a not exists or not in type query. This type of query returns records where no related child records exist. The ability to perform this type of query can be very useful. Referring again to the typical order-processing system, you can use this technique to find all customers who have not yet placed an order. To demonstrate this technique in the Help Desk application, let’s look at how to create a query to return engineers without associated issues. Just like before, Listing 10-4 shows the equivalent SQL that you would use to perform this query. Listing 10-4.  SQL equivalent of Not In query

314

Chapter 10 ■ Searching Data

To recreate this example, create a query called EngineersWithNoIssues and add the code shown in Listing 10-5 to the PreprocessQuery method of your query. Listing 10-5.  Returning all users who have never raised issues

This code works in the same way as the engineers with issues query. The simple difference with this example is that the code negates the condition inside the where operator.

Filtering by Date Elements The ability to filter records by date elements is a useful technique for you to understand. A typical use for this type of code is to find people who were born on a specific day and month. To demonstrate this technique, here’s how to create a query to return issue records that were raised during a specific month and year. To enable the end user to specify the month and year, create a query on the Issue table called IssuesByMonthAndYear and create two integer parameters called IssueMonth and IssueYear (Figure 10-8). Use the properties sheet to set the Is Optional property of both of these parameters to true.

315

Chapter 10 ■ Searching Data

Figure 10-8.  IssueMonth and IssueYear parameters Now, enter the code that’s shown in Listing 10-6. Listing 10-6.  Filtering by month and year parameter values

316

Chapter 10 ■ Searching Data

At this point, you can build a screen that uses this query by using the Editable Grid Screen (desktop application) or Browse Data Screen (HTML client) templates. Figure 10-9 shows an illustration of a screen that uses this query. The textbox control isn’t the friendliest control in which to enter month and year numbers. To improve this, you could use a custom control. Alternatively, you could create month and year lookup tables in your application. Although this might sound convoluted, this offers a simple solution that you can reuse in both HTML and desktop applications.

Figure 10-9.  Screenshot of the final screen

Top N Records A fairly simple but common requirement is the ability to return a top number of records in a given sequence. Let’s see a demonstration of how to create a query that returns the top five records from the Department table with the greatest floor area. To create this query, add a query based on the Department table called DepartmentsByFloorSpace. Now, add the code shown in Listing 10-7 to the query’s PreprocessQuery method.

317

Chapter 10 ■ Searching Data

Listing 10-7.  Top five departments with the greatest floor area

To order the results, this query calls the OrderByDescending query operator. The code supplies a lambda expression to indicate the property to order by. The take operator defines the number of records to return. In this case, the code returns the top five records. To improve this code further, you could add a parameter to enable the user to choose the number of records to return, rather than use a hardcoded value of five.

String-Matching Examples The simplest and most practical way for users to search data is to use free text criteria. However, in some circumstances, the pattern matching that LightSwitch applies on the built-in Search screens may not effectively return the records that the user is looking for. In this section, I’ll show you ways to offer more refined text searches.

Matching Non-Concurrent Words To understand the difficulties that users might encounter, let’s examine the behavior of LightSwitch’s builtin search feature. Figure 10-10 shows a Browse screen that contains issue records that relate to computer problems. Imagine a scenario where a user wishes to find all records that contain the words Dell and screen in the problem description.

318

Chapter 10 ■ Searching Data

Figure 10-10.  Search screen showing the results of a search The screenshot on the left part of Figure 10-10 shows the full set of records in the database. The screenshot on the right shows the search results when a user enters the criteria “dell screen” into the search box. The result of this search fails to return “issue 1.” This is because LightSwitch uses the contains operator, and therefore matches only the records where the words dell and screen appear next to each other. The search result clearly doesn’t return the expected results. Therefore, I’ll now show you how to match records where the search terms don’t appear concurrently in the record. The first step is to build a query that’s based on the Issue table. Name your query IssuesMatchAll and add a parameter called Criteria (Figure 10-11).

Figure 10-11.  Add a query parameter called Criteria Next, click the Write Code button and add the code in Listing 10-8 to the query’s PreprocessQuery method.

319

Chapter 10 ■ Searching Data

Listing 10-8.  Query to match non-concurrent words

The code in Listing 10-8 splits the criteria value into an array of separate words. The LINQ query applies the All operator to this array to test whether the problem description field contains all of the words in the array. Once you save your query, you can build a screen that’s based on this query. Figure 10-12 shows how the resulting screen now returns the expected result.

320

Chapter 10 ■ Searching Data

Figure 10-12.  Search screen showing correct records

Matching Multiple Words (Optionally) The previous example returns results that contain all of the search-criteria words that a user enters. Another common requirement is the need to return records that match some of words a user enters, rather than all. In this scenario, imagine that a user wants to find all issue records that relate to either HP or Dell computers. If the user enters “Dell HP” into the search box, the search returns zero results (Figure 10-13). The reason for this is that LightSwitch performs a match on records that contain the exact words Dell HP, and no such records exist.

Figure 10-13.  Search screen returns no matches for “dell hp”

321

Chapter 10 ■ Searching Data

Let’s see how to build a query to return records that match any of the words that the user supplies. The first step is to add a query that’s based on the Issue table. Name your query IssuesMatchSome and add a parameter called Criteria. Next, click the Write Code button and add the code that’s shown in Listing 10-9 to the query’s PreprocessQuery method. Listing 10-9.  Query to partially match one or more words

322

Chapter 10 ■ Searching Data

This code looks almost identical to the code in Listing 10-8. The main difference is that the code in Listing 10-9 applies the Any operator, as opposed to the All operator. After you save your query, you can create a Browse Data screen that’s based on this query. Figure 10-14 shows the final screen at runtime and illustrates how the result includes all records that contain the text Dell or HP.

Figure 10-14.  Search screen that shows the correct results

Case Sensitivity An important point about the examples in the book so far is that the searches are all case insensitive. For instance, if a user carries out a search on the word dell (with a lowercase d), the search results will include all records that include the word Dell, irrespective of whether the word is spelled with a lower- or uppercase d. When you carry out a search, LightSwitch coverts your query into a SQL statement. The collation sequence of the database determines the case sensitivity of the search results. The default collation sequence on a computer with US settings is SQL_Latin1_General_CP1_CI_AS (the CI in the collation name stands for case insensitive). This is the reason why the search results you see are case insensitive. You can change this behavior by changing to a case-sensitive collation on the table columns where you want to carry out case-sensitive searches. You would apply this change to your SQL Server database after you deploy your application.

Phonetic Searching It’s likely that some of your users will struggle to spell correctly. So, to make your application easier to use, you can develop Search screens that carry out phonetic-based “fuzzy” searches. This technique is particularly useful when you want to build screens to carry out searches against people. On one project I worked on, I developed a workflow that prevented users from entering new records until the user had carried out a phonetic search on existing records. You can use this technique to help minimize the occurrence of users entering duplicate records in a database. Figure 10-15 illustrates the end result of this example. It shows how, when a user carries out a search with an incorrect spelling of Mohammed, the output yields many likely results. The name Mohammed is a good example, because variations of this name exist that begin with Mu as well as Mo. This variation makes it difficult for users to carry out a “contains” search by entering the first few characters of the name.

323

Chapter 10 ■ Searching Data

Figure 10-15.  Search screen that shows the result of a phonetic search Let’s look at the steps you can carry out to add phonetic search capabilities to your application. First, create a query that’s based on the Engineer table. Name your query EngineerPhoneticSearch and add a parameter called Name. Next, click the Write Code button and add the code that’s shown in Listing 10-10 to the query’s PreprocessQuery method. Make sure to add an imports/using statement to the System.Data.Objects. SqlClient namespace.

324

Chapter 10 ■ Searching Data

Listing 10-10.  Query to carry out Soundex search

The code in Listing 10-10 uses Soundex. This popular algorithm converts the phonetic sound of a word into a numeric representation that is called a soundcode. This code calls the soundcode method in the SqlFunctions namespace to determine the soundcode of the search criteria and the engineer firstname. The code returns records where both of these match. Note that this code works only against records in the Intrinsic (or SQL Server) data sources.

325

Chapter 10 ■ Searching Data

Debugging Queries Most developers make mistakes while writing code, and a very difficult type of exception to diagnose is the runtime LINQ error. To illustrate this type of error, Figure 10-16 shows a query that intentionally contains an error.

Figure 10-16.  Example of an invalid LINQ query To the uninitiated, this query looks okay. For further reassurance, Visual Studio reports no errors, and the code even compiles perfectly. But at runtime, you’ll notice that there’s clearly a problem. In the case of a desktop application, LightSwitch displays a red X and tells you that it’s unable to load data. There’s very little information to help you determine the exact cause of the problem. Fortunately, the HTML client behaves better, because it actually gives you a meaningful error message (Figure 10-17).

Figure 10-17.  Runtime error behavior With this particular type of error, Visual Studio doesn’t break at runtime, even if you enable the option that appears in the Debug ➤ Exceptions dialog. A good technique you can use to diagnose query errors is to handle the Query_ExecuteFailed method. At runtime, you can place a breakpoint here and examine the queryDescriptor parameter to work out the cause of the error (Figure 10-18).

326

Chapter 10 ■ Searching Data

Figure 10-18.  Interrogate the queryDescriptor parameter for additional help The reason why this error occurs is because LightSwitch converts the LINQ expression to a SQL expression at runtime. An exception occurs because SQL Server has no method that is equivalent to the .NET method AddMonths. The compiler doesn’t detect this condition at compile time because it checks only for valid LINQ syntax. At compile time, LightSwitch doesn’t know what the underlying data store is—it could be Oracle or MySQL, as much as it could be SQL Server. Therefore, this error only manifests itself at runtime when LightSwitch attempts to convert the query to TSQL.

Walkthrough 10-2. Opening a Search Screen In the final part of this chapter, I’ll show you how to append a search feature to the header section of an HTML client application. This feature is a permanent fixture that always appears at the top of your application. Figure 10-19 shows the runtime view of this walkthrough. When a user enters a search term and clicks the Go button, the application opens the Issue Search screen and prepopulates the search criteria of the Search screen to the value that the user enters.

Figure 10-19.  Runtime view of search screen As a prerequisite, you should create the Browse Issue Search screen that I showed you at the start of this chapter (Walkthrough 10-1). There is, however, one slight modification you need to make to your Search screen. You should check the “Is parameter” checkbox in the properties sheet of the IssueProblemDescription property.

327

Chapter 10 ■ Searching Data

Once you modify your Search screen, open your default.htm file and add the code that’s shown in Listing 10-11. You can add this toward the end of your file, just before the closing body tag. Listing 10-11.  Opening a Search screen

At this point, you can run your application. When you enter a search term and click the Go button, the application opens the Search screen and filters the records by the problem description you enter. This code defines a DIV and applies CSS so as to position the textbox in the top-right section of the screen . The code defines an HTML textbox and a button. The code that handles the on-click event of the button opens the Search Issue screen. It passes the search criteria by using jQuery to determine the value that the user enters into the search textbox .

Summary A well-designed application makes it simple for users to find data. In this chapter, you learned several techniques to implement more-sophisticated search methods into your applications. Adding custom search into your application involves two parts: query design and screen design. The first part is to add a query to carry out the search. Your query will filter the underlying data source based on parameters you define. You can define parameters as optional. By doing so, users can choose not to provide a value, and LightSwitch will omit the filter clause that uses the parameter when the query executes. The second part is to create a screen that uses the query as the data source. When you create a new screen based on a query with parameters, LightSwitch adds local screen properties that bind to the query parameters. These local screen properties allow users to enter the search criteria at runtime. To filter by associated records, you can configure your screen to allow users to enter search criteria through data picker controls. To carry out more-sophisticated searches, you need to extend your query with LINQ code. The process to do this is to create a query and then to write code in the preprocess query method. This chapter showed you LINQ code you can use to filter records by child items and date elements. You also saw how to find records where child records either exist or do not exist. This type of filtering can be particularly useful. In traditional order-processing systems, you could use this type of query to identify customers who have placed, or have not placed, orders. You saw how to devise search queries to match more precisely against the text criteria that a user enters in order to provide better search results. This includes how to return records that contain all of the search criteria words a user enters and how to return records that include at least some of the words a user enters. You also saw how to implement phonetic searches using Soundex. This technique works effectively when you want to build screens to find users by name. Finally, I showed you how to use the Query_ExecuteFailed method to debug any runtime LINQ errors that you might encounter in your application.

328

Chapter 11

Building Practical Application Features In this chapter, I’ll describe techniques you can use to tackle typical requirements that you might find in business applications. This chapter will pull together content from previous chapters and show you the following: •

how to add file-storage capabilities to your application



how to integrate your application with GPS and mapping systems



how to develop screens that work against less common data structures

I’ll begin by showing you how to build screens to store documents such as Office documents and photos in your database. Next, I’ll describe screen-design techniques you can apply to various data structures. This includesscreens that users can use to select multiple records, screens to manage self-joined data, and screens that bind to a single row of data. Finally, I’ll describe GPS and mapping techniques and finish the chapter by describing code you can use to summarize data.

Working with Files The ability for users to upload and download documents such as spreadsheets, Word documents, and images can be very valuable. To start this chapter, I’ll describe the techniques you can use to add file-storage capabilities to your application. As a prerequisite, you need to define a table that includes a property with a data type of binary. In this chapter, I’ll use a table called IssueDocuments to demonstrate the coding techniques. Figure 11-1 shows the schema of this table.

329

Chapter 11 ■ Building Practical Application Features

Figure 11-1.  Table structure for document storage Once you have set up your data, the next step is to create screens that users can use to upload and download files. The screen-design techniques you use are significantly different for HTML and desktop applications, so I’ll begin by describing how to develop screens for the HTML client.

Adding File Support to HTML Client Applications The screen designer in LightSwitch doesn’t include file upload and download controls. To provide this functionality, you will need to develop custom controls, and in this section I’ll show you how.

Uploading Files There are two approaches you can take to add file-upload capabilities to your application. The first technique works only with HTML5 browsers, while the second technique provides compatibility with older browsers. In this section, I’ll show you how to build a custom control that attempts to use the HTML5 technique. If the client doesn’t support HTML5, the control automatically reverts to the legacy approach. HTML5 provides a standard way to interact with local files through the File API specification. By using this feature, you can work with files on the client before you send them to the server. This enables you, for example, to validate data or create thumbnails of images on the client without requiring a round trip to the server. We can use this feature to develop a file upload control; Figure 11-2 illustrates a high-level view of the control that we’ll build in this section.

330

Chapter 11 ■ Building Practical Application Features

Figure 11-2.  HTML 5 file-upload technique This technique relies on a custom control that consists of two elements: a File Browse button (i.e., an HTML input of type file) and a DIV that shows the results. When the user selects a file, the control uses the local file-processing feature of HTML5 to read the file. The custom control retrieves the contents as a base-64 encoded string, adds the data to the local change set, and shows the results in the DIV. When the user clicks the Save button, the HTML client calls the data service’s Save operation. The change set that the client sends to the server includes the file that the user selects. Although the HTML5 File API is simple and efficient, a disadvantage is that not all users use modern HTML5-compliant browsers. Therefore, it is necessary to devise a fallback method to maintain compatibility with older browsers. If a user uses an older browser, the custom control automatically reverts to a backwardly compatible technique, which is illustrated in Figure 11-3.

331

Chapter 11 ■ Building Practical Application Features

Figure 11-3.  Non HTML5 File Upload Technique As Figure 11-3 shows, if the custom control detects that the client browser isn’t HTML5 compliant, it generates a control that contains three elements: a File Browse button, a hidden iframe, and a DIV that shows the progress details (an iframe is an HTML control that displays a web page inside another web page). Once the user selects a file, the control submits the file to a server-side ASP.NET HTTP handler via the hidden iframe. This iframe enables the browser to submit the file to the server without interrupting the user’s ability to interact with the other parts of the screen. The HTTP handler mimics the job that the HTML5 File API would carry out. It produces a base-64 encoded representation of the file and returns the result to the client. When the HTTP handler returns the result, the contents of the hidden iframe will contain the base-64 representation of the file. The custom control detects when the iframe finishes loading and displays the progress detail DIV in the same way as the HTML5 custom control does.

Building a Custom File Upload Control Now that you have some understanding of how this technique will work, let’s write the JavaScript code to generate the custom control. To do this, go to your HTML client project and create a new JavaScript file in your Scripts folder. Name your file prols-controls.js and add the contents shown in Listing 11-1.

332

Chapter 11 ■ Building Practical Application Features

Listing 11-1.  File upload custom control (prols-controls.js)

333

Chapter 11 ■ Building Practical Application Features

334

Chapter 11 ■ Building Practical Application Features

To add a file upload control to a screen, you would call the createfileUploader method from the render method of a custom control. To make this code available in your application, you need to add a link to the prols-controls.js file in your default.htm page. You can do this by adding the following tag to the lower part of your page, just before the end of the body tag:

Supporting Non-HTML5 Browsers The next part of this solution is to create the HTTP handler to support non-HTML5-compatible browsers. This handler accepts a file and returns the base-64 representation. In the root of your server project, create a folder called Content. Inside this folder, create a subfolder called DocUtils. Right-click the DocUtils folder and select the “Add > Generic Handler” menu item. Name your new handler GetBase64String.ashx (Figure 11-4). If the “Add > Generic Handler” menu item doesn’t appear, you can use the “Add > New Item” menu item instead.

335

Chapter 11 ■ Building Practical Application Features

Figure 11-4.  Adding a new generic handler Next, modify the contents of the ProcessRequest method as shown in Listing 11-2. Listing 11-2.  Creating a page that returns the base-64 representation of a file

336

Chapter 11 ■ Building Practical Application Features

The code on this page carries out a relatively simple task. It produces the same response that the HTML5 FileReader generates. It uses the .NET Convert method to base-64 encode the file content and adds the preamble of "data:{mime-type};base64," to the start of the response .

Adding a File Upload Control to Your Screen The final part of the solution is to add your custom control to a screen. Here are the screen-design steps to build a screen to enable users to upload files into the IssueDocument table: 1. Use the Common Screen Set template to create a set of screens for the IssueDocument table. 2. Open the AddEditIssueDocument screen. Set the control type for the Issue File data item to “Custom Control.” 3. In the properties sheet for the IssueFile custom control, click the Edit Render Code link. Add the code that’s shown in Listing 11-3. 

337

Chapter 11 ■ Building Practical Application Features

Listing 11-3.  File upload JavaScript code

At this point, you can run your application. Figure 11-5 shows the appearance of the Add/Edit Issue Document screen.

Figure 11-5.  Document upload control at runtime As Figure 11-5 shows, the custom control displays a Browse button. After the user selects a file, the custom control adds the document to the local change set. Once this process completes, the custom control displays a confirmation message on the screen. Notice that the screen highlights the issue file custom control in red. This is because the IssueDocument table defines Issue File as a required field. If you don’t like this red coloration, you can disable it by setting the “Validation Rendering” option to Custom in the properties sheet of the custom control.

Downloading Files The ability to upload files is just one half of this solution. Users need some way to retrieve files that are stored in the database, and in this section I’ll show you how to implement this feature. We’ll use LightSwitch’s Server Application Context API. This feature enables clients to communicate directly with the LightSwitch middle tier without having to go through the Save or Query pipelines. Figure 11-6 shows a high-level overview of how this download function will work.

338

Chapter 11 ■ Building Practical Application Features

Figure 11-6.  Downloading files via the Server Application Context API By using the Server Application Context API, you can access your data workspace from custom .NET applications. This, for example, allows you to create ASP.NET or MVC applications that can access your LightSwitch data. You can use the Server Application Context API to add custom functions to your application’s server project, which you would do by creating an HTTP handler. To create a handler that returns the file contents, navigate to your server project, right-click the folder \Content\DocUtils, and add a new generic handler. Name your handler DownloadIssueDocument. ashx. Now, modify the contents of the ProcessRequest method, as shown in Listing 11-4.

339

Chapter 11 ■ Building Practical Application Features

Listing 11-4.  Issue file download code

340

Chapter 11 ■ Building Practical Application Features

The DownloadIssueDocument.ashx handler provides a URL endpoint that users can call to download issue documents. For example, the URL http://WebServer/Content/DocUtils/DownloadIssueDocument. ashx?id=8 would return the document that’s attached to the IssueDocument record with an ID of 8. The final step is to add a hyperlink to the ViewIssue Document screen. In the screen designer, add a data item for the ID property of the IssueDocument table. In the properties sheet, change the display name setting to Issue File (Figure 11-7). Also, set the “Disabled Rendering” and “Read-Only Rendering” options to Custom.

341

Chapter 11 ■ Building Practical Application Features

Figure 11-7.  Configuring a custom control In the properties sheet, click the Edit Render Code link and add the code that’s shown in Listing 11-5. Listing 11-5.  Custom control code to show a Download Document File hyperlink

This code builds a hyperlink and sets the target to the Download Issue Document ASHX handler. The first part of this code builds the initial part of the URL (http://WebServer/) . It sets the value to be identical to the root URL of the LightSwitch application. Next, the code appends the ID value of the selected document record to the URL  The next line builds the HTML anchor tag and sets the target attribute to _blank.  This prompts the browser to open the hyperlink in a new window. If you don’t specify this attribute, the hyperlink would navigate the user away from your LightSwitch application. You can now run your application; Figure 11-8 shows how the View Document screen looks at runtime.

342

Chapter 11 ■ Building Practical Application Features

Figure 11-8.  Final screen showing Download Document File hyperlink You might wonder why we set the “Disabled Rendering” option on the control to disabled earlier in this task. If you were to retain the default setting of automatic, LightSwitch disables the hyperlink on the custom control and prevents the user from downloading the file. The automatic setting makes the hyperlink non-clickable, because the ID property that the custom control binds to is non-editable. To further improve this code, you could add code to prevent the hyperlink from showing if the file content is empty, or improve the presentation of the control by adding a hyperlinked image that triggers the download.

Working with Mobile Device Cameras All modern mobile devices have built-in cameras. Certain types of applications can benefit greatly from camera integration. For example, estate agent or surveying applications could include a feature that enables the user to take a photo. With HTML5, it’s very simple to add a File Upload button that opens the built-in camera. In the custom control code I showed you earlier (Listing 11-1), the file upload control generates an HTML input with the type attribute set to file. To configure the File Upload button so that it opens the built-in camera, you simply modify the custom control code so that it generates an HTML input with the accept and capture attributes populated, as shown in Listing 11-6. Listing 11-6.  Opening a mobile device’s camera or microphone

If you now run your application on a mobile device, the File Upload button will open the built-in camera rather than show the File Browse dialog. The majority of up-to-date browsers on Android or iOS devices will support this behavior. As Listing 11-6 illustrates, you can also set the capture mode so that it opens the video recorder or voice-recording application on the mobile device instead.

Adding File Support to Desktop Client Applications So far, I have showed you how to add file upload and download capabilities to a HTML client application. In this section, I’ll show you how to add the same features to a desktop application.

■■Caution  Note that the code sample in this section applies only to desktop applications in desktop client mode. This code will not work for desktop applications in web client mode.

343

Chapter 11 ■ Building Practical Application Features

Uploading Files Fortunately, it’s easier to add a file upload control to a desktop application than to an HTML client application. Let’s review the steps to add a file upload control to a New Data screen that binds to the IssueDocument table. Once you create your data-entry screen, the first step is to add a new button to it. Name your button UploadFileToDatabase and add the code shown in Listing 11-7. Listing 11-7.  Uploading a file in desktop clients

344

Chapter 11 ■ Building Practical Application Features

345

Chapter 11 ■ Building Practical Application Features

To display the Silverlight File Open or Save dialogs, you must call code that executes on the main UI thread . This is because the file dialog represents a UI task, and the logic must therefore run on the UI thread. The File Open dialog  displays a control that allows the user to select a file. Once the user selects a file, the code reads the file data into a byte array using a FileStream object . It then assigns the data to the IssueFile property . Next, the code saves the filename and file extension of the document in the same block of code. You can set the File Open dialog’s Filter property to limit the file types that the user can select. This example configures the dialog to show all files by setting the *.* filter, but you could supply a list of pipe-delimited file extensions and descriptions with which to apply the filter (as shown in the commented-out line of code). A very important point is that this code works only in desktop applications. It won’t work in a browser-based desktop application. If you attempt to run this code in a browser application, you’ll receive the security exception “Dialogs must be user-initiated.” This is because the button code runs on the screenlogic thread, and by subsequently invoking the File Open dialog on the main UI thread, Silverlight loses the fact that the action was indeed user initiated. Desktop applications don’t suffer from this problem, because the elevated trust of a desktop Silverlight application allows you to open the file dialog from any code. In a browser application, the code that launches file dialogs must be at the top of the call stack. If you wish to use the Silverlight file dialogs in a browser application, you can do so by creating a custom button control and handling the button’s click event.

■■Note  When you create commands that work only in desktop applications, it’s a good idea to disable your command in browser applications by writing code in your command’s CanExecute method (UploadFileToDatabase_CanExecute in this example). Chapter 22 describes this process in more detail.

346

Chapter 11 ■ Building Practical Application Features

Downloading and Saving Files To allow users to open the files that are stored in the database, you can build a File Save feature to save files locally on the end-user PC. In this section, I’ll show you how to open a File Save dialog to enable the user to choose where to save the file. To create this feature, create a Details screen based on the IssueDocument table and name it IssueDocumentDetails. Create a new button on your screen and call your method SaveFileFromDatabase. Add the code shown in Listing 11-8. Listing 11-8.  Downloading a file

347

Chapter 11 ■ Building Practical Application Features

348

Chapter 11 ■ Building Practical Application Features

Just as before, this code must execute on the main UI thread for the Save File dialog to display correctly . The Save dialog prompts the user to enter a filename and location . The final part of this code writes the data to the file using a MemoryStream object .

Opening Files with the Default Application A slight disadvantage with the previous approach is that it’s not very joined up. Once the file save operation completes, the user needs to locate and open the file outside of LightSwitch. To improve this behavior, you can create a button that a user can click to download and open the file in the default application (Figure 11-9).

Figure 11-9.  Opening files in the registered application In this example, I’ll show you how to add a button to a screen that binds to an issue document record. When a user clicks this button, the application starts the registered application and opens the document that’s associated with the record. This technique consists of two main steps: •

Save the file to an interim file location.



Use the shell execute method to start Word and open the saved file.

Because this code calls automation code to open an application on the client PC, the security restrictions in Silverlight will prevent this technique from working in a browser application. On a related issue, the initial step of this sample saves the file onto the local file system. The security restrictions in Silverlight limit the places where you can save files. These limitations depend on the technique you use to save your file and are described in Table 11-1. Table 11-1.  Ways to Save a File in a Desktop Application

Method

Description

Use the classes in the System.IO namespace

You can only save files in specific locations. These include the My Documents, My Music, My Pictures, and My Videos folders of the current user.

Use the Silverlight SaveFileDialog dialog

You can save files to any location that the user has permissions to read/write.

Use isolated storage

This is a virtual file system that Silverlight provides.

349

Chapter 11 ■ Building Practical Application Features

If you want to save a file to a temporary location without any user intervention, there are two options you can choose from. You can create your file in the My Documents folder or you can create the file in isolated storage. Isolated storage is a virtual file system that Silverlight provides. The isolated storage location is a hidden folder that exists on the end user’s machine. This makes it an ideal place to save temporary files. However, the disadvantage of using isolated storage is that Silverlight imposes a default storage quota, and administrators can also specify additional storage quotas. Therefore, there’s no guarantee there’ll be sufficient space for you to save your file. This example saves the temporary file in the My Documents folder, but the code includes a comment that shows you how to use isolated storage instead. To create this example, open the Issue Document Details screen and create a new button called OpenFileFromDatabase. Add the code from Listing 11-9. Listing 11-9.  Opening files in their default applications

350

Chapter 11 ■ Building Practical Application Features

351

Chapter 11 ■ Building Practical Application Features

The first part of the code builds the path where you’ll save your file . It then saves your data into this file  and opens it by calling the Shell command .

Validating File Sizes To round off this section, let’s look at a technique you can use to impose a maximum size on files that are stored in your database. By providing a size limit, you can prevent users from bloating the size of your database. To implement this feature, you must apply validation at the entity level. This means that your validation logic will apply both to HTML and desktop clients. Listing 11-10 shows the code used to prevent users from uploading files that are larger than 2MB. Listing 11-10.  Validating file sizes

352

Chapter 11 ■ Building Practical Application Features

LightSwitch exposes Binary and Image properties in code as byte arrays. The code in this listing calculates the file size in megabytes by dividing the byte array length by 1,048,576. If you want to calculate the size in kilobytes, you would divide by 1,024 instead. Table 11-2 shows the conversion values that you would use. If you need to carry out many conversions, it would be a good idea to add this logic into a helper method. Table 11-2.  Converting Byte Array Length

Unit of Measurement

Divisor

Kilobyte (KB)

1,024

Megabyte (MB)

1,048,576 (1,024 ȅ 1,024)

Gigabyte (GB)

1,073,741,824 (1,024 ȅ 1,024 ȅ 1,024)

Terabyte (TB)

1,099,511,627,776 (1,024 ȅ 1,024 ȅ 1,024 ȅ 1,024)

Selecting Multiple Records In some scenarios, you can improve productivity by providing functions that can work against multiple records. For example, an invoicing system might contain a checkbox list of all available products. A user could check all the products that a customer wants to purchase and click a button to add the products to the order. An important design task is to devise a screen that allows the user to select multiple records. In this section, I’ll show you how to accomplish this in an HTML client application. To demonstrate the technique, I’ll show you how to build a checkbox list that a user can use to close multiple records with a single click of a button (Figure 11-10).

353

Chapter 11 ■ Building Practical Application Features

Figure 11-10.  Multi-record selection technique Unfortunately, there isn’t a straightforward way to construct this type of user interface. You could try to accomplish this by storing the selected items in a temporary table and adding code to the Save pipeline to carry out the bulk operation. The benefit of this technique is that it aligns closely with MVVM principles, and you can easily reuse the server-side objects and code in both desktop and HTML client applications. But, in practice, storing multiple selections in temporary tables is messy. You need to pre-populate the temporary tables with data, make sure to store the user selections against the correct session (a user could open multiple copies of your application or open multiple screens), and clean up the data in the temporary table afterward. Therefore, I'll describe an alternative method that works by rendering an unbound checkbox against each item in a list. Compared to using temporary tables, this technique is simple and relatively selfcontained. This approach consists of a custom control that includes a checkbox and issue description. When a user selects an item, the screen stores the selected issue ID value in an array. Once the user chooses all the required records, the user can complete the action by clicking a button on the screen. This button calls a web method that performs the bulk data operation using the Application Server Context API. To create the custom control, use the Browse Data Screen template to add a screen that is based on the issue table. Change the tile list control to a list control, remove the Item Tap action for the list control, change the group beneath the control to a custom control, and remove any child controls beneath the custom control. Figure 11-11 shows the appearance of this screen in the designer.

Figure 11-11.  Multi-record selection technique

354

Chapter 11 ■ Building Practical Application Features

In the properties sheet for the custom control, click the Edit Render Code link and add the code that’s shown in Listing 11-11. Listing 11-11.  Custom control code to add a checkbox and description

This code generates the HTML content for each row in the list control. It creates a checkbox control  and a label  with the issue subject title. The code uses jQuery to add an event handler for the click event of the checkbox . This code adds or removes the issue ID value from the array of selected issues. To enable you to identify each checkbox in client-side code, this code sets the ID of each checkbox control to a unique identifier that begins with a chk prefix and ends with the primary-key value . To add the code that defines the array of selected issues and the helper methods to add and remove items, add a new JavaScript file to your Scripts folder. Name your file prols-multiselect.js and add the code that’s shown in Listing 11-12. Once you create this file, add a reference to it in your default.htm file, as shown in Listing 11-12

355

Chapter 11 ■ Building Practical Application Features

Listing 11-12.  Multi-select JavaScript helper files

This completes the code that stores the selected items. To build the screen button code that closes the selected issues, add a button to your screen and choose the option to write a custom method. Name your method CloseIssues and add the code that’s shown in Listing 11-13.

356

Chapter 11 ■ Building Practical Application Features

Listing 11-13.  Issue Closure screen button code

The code in Listing 11-13 calls a web method to perform the issue-closure operation. Specifically, the code retrieves a comma-separated list of the selected ID values  and posts the results to the web method . When the operation succeeds, the code displays a message box that contains the result from the server and finishes by clearing the checkboxes on the screen. To ensure that the array is empty when the screen opens, this listing contains code that clears the array when the user first opens the screen . To create the server-side web method, add a new handler file in the content folder of your server project called CloseIssues.ashx. Next, add the ProcessRequest code that’s shown in Listing 11-14.

357

Chapter 11 ■ Building Practical Application Features

Listing 11-14.  ASHX handler code to close multiple issues

358

Chapter 11 ■ Building Practical Application Features

At this point, you can run your application and use your screen to close multiple issues. The first part of this code splits the CSV data into an array . Next, the code loops through the array of ID values and uses the Server Application Context API to access each issue record. The code sets the closed date value of each issue record  and calls the SaveChanges method  to save the changes to the database. Finally, the code returns a message to the caller . Note that in this example, I implemented the issue-closure functionality through a server-side method. I chose this method in order to demonstrate a mechanism that you can extend so as to apply additional server-side logic. For this particular example, however, you could simplify your code by modifying the data on the client, rather than passing the task to a server-side method.

359

Chapter 11 ■ Building Practical Application Features

■■Note  In the case of desktop client applications, it’s not simple to add an unbound checkbox that calls custom code. I’ll show you later in this book how to accomplish this type of UI by creating a custom control.

Assigning and Unassigning Self-Joined Data At some point, you may encounter the need to manage self-joined data. You usually encounter this type of data structure in systems that model hierarchies. If you attempt to create a screen that manages self-joined data, your screen may not work as you expect. To explain this further, let’s look at what happens when you build a screen that’s based on the Engineer table. This table includes a self-join that stores the manager/ subordinate relationship for each engineer (Figure 11-12).

Figure 11-12.  Self-join in Engineer table If you create a Details screen for the Engineer table and include the Engineer Subordinates data item, you end up with a screen that looks like Figure 11-13.

Figure 11-13.  Default subordinate data grid

360

Chapter 11 ■ Building Practical Application Features

By default, LightSwitch renders the subordinate collection as a data grid. The biggest problem with this screen is that the Add and Delete buttons on the data grid perform the addition and deletion of engineer records, rather than the assignment and de-assignment of subordinates. To allow users to assign subordinates, you can add a control that enables the user to select an engineer and then add a button that carries out the assignment. To de-assign an engineer, you can add a button to de-assign the selected engineer in a list. Let’s go over the steps to add a subordinate assignment feature to an Engineer screen. First, create a screen that’s based on the Engineer table. In the case of a desktop application, use the Details Screen template, whereas for an HTML client application, use the Add/Edit Details Screen template. In the Add New Screen dialog, include the Engineer Subordinates data item so that you can see the related engineer records. Now, carry out the following steps in the screen designer: 1. Add a local property called EngineerToAdd. 2. Drag the EngineerToAdd property onto your screen to create an auto-complete box control (for a desktop application) or a details picker control (for an HTML client application). 3. Create a button called AssignSubordinate and add the AssignSubordinate code, as shown in Listing 11-15. To add a button to un-assign an engineer as a subordinate, carry out the following tasks: 1. For a desktop application, change the subordinate data grid to a data list. Next, create a button on your screen and name it DeassignSubordinate. 2. For an HTML client application, change the subordinate tile list control to a table control and add a button called DeassignSubordinate inside the table row. Unlike with desktop applications, users cannot select a row in a list here, and the workaround is to add a Deassign button against each subordinate record in a table (Figure 11-14).

Figure 11-14.  Example screen design (HTML client)

361

Chapter 11 ■ Building Practical Application Features

3. Add the DeassignSubordinate code, as shown in Listing 11-15.  Listing 11-15.  Assigning and deassigning subordinates

362

Chapter 11 ■ Building Practical Application Features

The Assign Subordinate button adds the selected engineer to the engineer’s subordinate collection . In practice, you may want to write additional code to check that the user hasn’t left the auto-complete box blank. The Deassign Subordinate button removes the engineer that’s selected in subordinates data list . For desktop applications, assigning and deassigning engineers to the subordinates collection doesn’t automatically refresh the data list of subordinates (calling the refresh method alone on the subordinates collection won’t work either). The simplest way to address this problem is to save and refresh your screen . However, note that this may not be ideal, because it saves all changes that have been made on the screen. Therefore, you might want to add a confirmation message to check that the user wants to carry out the save. The code for HTML client applications works slightly differently. To assign an engineer as a subordinate, the code sets the Manager property for the subordinate engineer. To unassign an engineer, the code clears the Manager property for the subordinate engineer. When you now run your screen, you’ll be able to assign and deassign subordinates as shown in Figure 11-15.

Figure 11-15.  Subordinate allocation grid

363

Chapter 11 ■ Building Practical Application Features

Creating Screens to Work with Single-Row Tables A useful design technique is to build a table that stores only a single row of data. An ideal use for this type of structure is to store application configuration settings. In this section, I'll show you how to create a screen that’s based on a table called AppOption (Figure 11-16). This table allows administrators to control application settings, such as reporting configuration and email settings.

Figure 11-16.  AppOption table To create a screen that binds to the first record in a table, the first step is to create a new screen. For desktop applications, create a New Data screen and set the data source of the screen to be the table you want to use—in this case the AppOption table. Now, add the code in Listing 11-16 to the InitializeDataWorkspace method. The steps to carry out for an HTML client application are slightly different. In this case, select the Browse Data Screen template and leave the screen data drop-down blank. The reason for choosing the Browse Data Screen template is because LightSwitch automatically adds an entry in the application’s navigation menu for screens that are based on this template. Name your screen AppOptionsEdit and carry out the following additional steps: 1. Click the Add Data button and add a local AppOptions property called AppOptionProperty. 2. Create data controls for the AppOptionProperty property by dragging the properties from the screen member list onto your screen. By default, LightSwitch adds AppOptionProperty as a summary control. Change the summary control to a rows layout in order to create data controls for each data property in theAppOptionProperty property. By default, the AppOptionProperty controls will be read-only. Uncheck the “Use Read-only controls” checkbox on the rows layout, or change the controls to be editable controls.

364

Chapter 11 ■ Building Practical Application Features

3. Add a button to your screen to allow the user to save the record. Name your button SaveAppOption. Figure 11-17 shows how your screen should now look.

Figure 11-17.  Screen design of a single-record edit screen

365

Chapter 11 ■ Building Practical Application Features

4. Add the code for the screen create method and the code that runs when the user clicks the Save button, as shown in Listing 11-16.   Listing 11-16.  Creating a screen that works only with the first record

366

Chapter 11 ■ Building Practical Application Features

For desktop applications, the New Data Screen template creates a screen with controls that bind to a property called AppOptionProperty. The first part of the code sets the property to the first record in the table by calling the FirstOrDefault method . If the method returns null, the table is empty. In this case, the code assigns a new instance of an AppOption entity to the AppOptionProperty. The logic in the HTML client example works in the same way. The code in the created method calls a query that calls the top(1) method so as to return the first row in the table . This code uses the promise pattern to execute the query asynchronously. If a record exists, the code sets the AppOptionProperty property to the first (and only) record that the query returns. Otherwise, the code assigns a new instance of an AppOption entity to the AppOptionProperty property . The code that runs when the user clicks the Save button calls the saveChanges method on the data workspace. When the save operation succeeds, the code returns the user back to the previous screen. You can now run your application; Figure 11-18 shows the appearance of the HTML client version of this screen at runtime.

367

Chapter 11 ■ Building Practical Application Features

Figure 11-18.  Application options screen

Nesting Data-Selection Controls To round off this section of UI features, let’s look at a simple and useful technique that you can apply during screen design. This technique involves linking sets of detail-picker controls or auto-complete boxes. To give an example in the context of an automotive application, you could build a drop-down list of car manufacturers. When a user selects a manufacturer, the screen will populate a drop-down list of car models that are associated with the manufacturer. To demonstrate this technique, I’ll show you how to build a Search screen that filters issue records by assigned engineer. This screen contains a control that shows a list of departments. When the user selects a department, the screen populates a second control that shows the engineers that belong in the department. To create this example, create the engineer and department tables as shown in Figure 11-19. As this diagram shows, a (zero-or-one)-to-many relationship exists between the department and engineer tables.

368

Chapter 11 ■ Building Practical Application Features

Figure 11-19.  Engineer and Department tables The next step is to create two queries. The first query returns a set of issues that are filtered by the assigned engineer. This query populates the main data control on the screen. The second query returns engineer records that are filtered by department. The purpose of this query is to populate the control that shows the list of engineers. Figure 11-20 illustrates these two queries. The first query is called IssuesByEngineer and filters the assigned engineer ID by an integer parameter called AssignedToId. The query that filters engineer records by department is called EngineersByDepartment. This query is based on the Engineer table and filters the DepartmentId property by a parameter called DepartmentId.

369

Chapter 11 ■ Building Practical Application Features

Figure 11-20.  IssuesByEngineer and UsersByDepartment queries Let’s review the screen-design steps to carry out once you create the two queries. For HTML client applications, create a screen that's based on the Browse Data template. For desktop applications, create a screen that's based on the Editable Grid Screen template. In both cases, choose the IssuesByEngineer query as the data source for your screen. Now, carry out the following steps in the screen designer: 1. Click the Add Data Item button and add a local Department property to your screen. Name your property DepartmentProperty. Next, add an Engineer property to your screen and name it EngineerProperty. 2. Drag DepartmentProperty and EngineerProperty onto your screen. For a desktop application, set the control type of both properties to the auto-complete box control. For an HTML client application, set the control type to the detail picker control. 3. To add more meaningful descriptions to these properties, you can change the description of DepartmentProperty to “Show users by department” and the description of the EngineerProperty to “Select Engineer.” 4. Click the Add Data Item button, select the Query radio button, and add the EngineersByDepartment query to your screen. Figure 11-21 illustrates how the HTML client version of the screen now looks.

370

Chapter 11 ■ Building Practical Application Features

Figure 11-21.  Screen designer view of screen The next step is to configure the query parameters. Figure 11-22 illustrates the following three steps to carry out in the screen designer: 1. Set the DepartmentId parameter value of the EngineersByDepartment query to DepartmentProperty.Id. 2. Open the properties sheet for the EngineerProperty auto-complete box or detail picker control. Use the Choices drop-down to set the data source to EngineersByDepartment. 3. Set the AssignedToId parameter value of the IssuesByEngineer query to EngineerProperty.Id.

371

Chapter 11 ■ Building Practical Application Features

Figure 11-22.  Query parameter binding At this point, you can run your application (Figure 11-23). When you open this screen, you can choose a department. Once you select a department, the screen sets the engineers control to only show engineers who belong to the department you select. When you select an engineer, the main section of the screen will show all issue records that are assigned to that engineer.

Figure 11-23.  Nested detail picker control at runtime

372

Chapter 11 ■ Building Practical Application Features

Working with Locations Most modern mobile devices include GPS, and, because of this, location-based applications are very common. In this section, I’ll describe techniques you can use to add location-based functionality to your HTML client applications. I’ll show you how to determine the location of a user and how to plot locations on a map.

Picking Up GPS Locations You can determine the location of a device by writing JavaScript code. In this section, I’ll show you how to add a button to a screen that binds to a department record. When the user clicks the button, the code will populate the Longitude and Latitude fields on the screen. To follow this example, create a set of screens for the Department table by using the Common Screen Set template. The screenshot in the previous section shows the schema of this table. Next, open the Add/Edit Department screen and add a button called GetLocation. Now, add the code that’s shown in Listing 11-17. Listing 11-17.  Picking up the GPS location

When you run this screen and click the button, the code will populate the longitude and latitude properties, as shown in Figure 11-24. This code uses the JavaScript navigator object. This object provides details about the browser, and you can use it to find properties including the browser name and version. Most importantly, the navigator object provides access to the geolocation object, which you can use to determine the geographical location of a user.

373

Chapter 11 ■ Building Practical Application Features

Figure 11-24.  Determining a user’s location The location results will depend on the browser and device. The Chrome and Firefox browsers on PCs use Google’s location service to estimate your location. Google’s service uses the signal strength of WiFi access points and information about your router and IP address to estimate a location. If you open your application on a device with GPS, the Geolocation API will likely use a GPS reading. The result from the getCurrentPosition method enables you to determine the longitude and latitude of the device. If available, you may be able to determine other location properties such as altitude, heading, or speed. These properties are summarized in Table 11-3.

374

Chapter 11 ■ Building Practical Application Features

Table 11-3.  getCurrentPosition Properties

Property

Description

Latitude

The latitude value in decimal degrees

Longitude

The longitude value in decimal degrees

Accuracy

The accuracy of position

Altitude

Altitude, measured in meters above the mean sea level

altitude Accuracy

The accuracy of the altitude

Heading

Heading, measured in degrees clockwise from north

Speed

Speed, measured in meters per second

If you’re unfamiliar with geolocation, the longitude and latitude readings that the getCurrentPosition method returns (in decimal degrees) might not be very meaningful. Therefore, Figure 11-25 illustrates these values in the form of a diagram.

Figure 11-25.  Longitude and latitude measurements

375

Chapter 11 ■ Building Practical Application Features

When you call getCurrentPosition, you can specify an error handler and timeout, and it’s useful to do this to prevent the geolocation code from hanging your application. Finally, it’s worth noting that the accuracy of GPS readings can vary. When you call the getCurrentPosition method for the first time, there may not be sufficient time for the device to turn on the GPS and lock onto sufficient satellites to give an accurate reading. In this situation, the Geolocation API tends to return the last known location. Because of this, second or subsequent calls to getCurrentPosition will usually return a more accurate location.

Integrating with Mapping Systems To help visualize locations, you can use mapping services to display the location data in your database. Let’s review how to use Google maps to display the locations that you store in your database. I’ll show you how to embed a map on a screen that binds to a department record. This map will include a pinpoint to highlight the location of the department record. To display a Google map on a web page, there are two main steps to carry out. The first step is to add a DIV onto your page to host the map control. The second step is to initiate the map with JavaScript code and to supply the location that you want the map to show. To render a Google map on a screen, you need to create a custom control to host the map. First, create a View Details screen and set the department table as the data source. Next, add a custom control that binds to the Department property. To do this, drag the Department property onto your screen and use the drop-down to change the control type to Custom Control (Figure 11-26).

Figure 11-26.  Screen designer view of Department screen Next, add the following line into the body section of your default.htm file:

Finally, add the render code for your custom control as shown in Listing 11-18.

376

Chapter 11 ■ Building Practical Application Features

Listing 11-18.  Adding a Google map

The code in Listing 11-18 defines a DIV to host the map control . The next section defines the code that runs when the DIV is ready. This code determines the longitude and latitude values of the department record  and uses these values to configure the options of the map. The final line of code initializes the map with the options that you define . At this point, you can run your screen; Figure 11-27 illustrates the appearance at runtime. 

377

Chapter 11 ■ Building Practical Application Features

Figure 11-27.  Map screen at runtime

■■Note  If you want to use Bing maps instead of Google maps, you can find a code sample on the official MSDN help site. However, the official sample is more complicated, because it uses the Bing Developer API, which requires you to first register and obtain a Bing Maps authentication key.

378

Chapter 11 ■ Building Practical Application Features

Summarizing Data In the final part of this chapter, I’ll show you how to produce counts and sums of data. A practical example of where you could apply this could be on a Line Item screen in an order system. This type of screen often contains a running total of the quantities and prices. The second purpose of this section is to highlight the technical way in which LightSwitch produces the count.

Showing Aggregate Counts/Sums/Averages To explain how to generate sums of data, this section develops a timesheet feature that enables engineers to record the time that they’ve spent on issues. The Data Entry screen will include a running sum of the time. Figure 11-28 shows the schema of the timesheet table.

Figure 11-28.  Schema of timesheet table For HTML client applications, add a Browse Data screen based on this table. For desktop clients, add an Editable Grid screen. For both application types, click the Add Data Item button and add a local property called TotalMinutes. Set the data type of this property to double. The purpose of this property is to store a running count of the time duration. Drag this property onto the screen designer to create a data control for this property (Figure 11-29).

379

Chapter 11 ■ Building Practical Application Features

Figure 11-29.  Create a property called TotalMinutes and drag it onto the design surface

For HTML client applications, select the data control that binds to the Timesheet collection. This would be the tile list control, or the list or table control if you decided to change the control type. Now, open the properties sheet and click the Edit Postrender Code link. Enter the code that’s shown in Listing 11-19. In the case of a desktop application, select the Timesheet collection, click the Write Code button, and add code to the Changed method as shown in Listing 11-19. Listing 11-19.  Calculating sums

380

Chapter 11 ■ Building Practical Application Features

At this point, you can run your application; Figure 11-30 shows the appearance at runtime. Let’s get a brief explanation of how this code works. In the HTML client example, the first part of the code databinds the DurationMins property to a function. This function iterates through the items in collection to work out the sum.

Figure 11-30.  Screen at runtime showing a count of total minutes In the case of the desktop application, the code uses the LINQ Sum operator to determine the sum.

381

Chapter 11 ■ Building Practical Application Features

Querying Data Remotely An interesting aspect of the .NET code in the previous section is that LightSwitch sums the data locally. To illustrate this concept further, let’s take a look at the slightly more complex example that’s shown in Listing 11-20. This code is based on an Engineer Detail screen. Listing 11-20.  Querying data collections

This code returns a count of engineer issues that have been created since the start of the year. Although query 1 looks very similar to query 2, there’s a big difference between these two code samples. The data source for query 1 is a navigation property. Navigation properties are of type EntityCollection. Technically, LightSwitch carries out any queries against a navigation property locally. The code in query 2 calls the Query method. This method returns an IDataServiceQueryable, and the main difference between this and an EntityCollection object is that LightSwitch can delegate the task of filtering the data to the SQL Server.

382

Chapter 11 ■ Building Practical Application Features

In this particular example, each engineer could be associated with hundreds or even thousands of issue records. Therefore, it’s much more efficient to perform this query remotely. Figure 11-31 illustrates the actual SQL that SQL Server executes by highlighting the output from SQL Server Profiler. This output proves that when you use Query as a data source, SQL Server carries out the filtering, not LightSwitch.

Figure 11-31.  The SQL Profiler result of querying navigation properties and IDataServiceQueryables

Merging Data Although it might seem more efficient to perform your querying remotely, there are good reasons to query your data locally. If the data that you want to use is already loaded on the client, it’s quicker to query the data that’s already there. Also, not all standard query operators support remote execution, and there may be features you want to include that you can achieve only with a local query. To demonstrate such a feature, let’s look at an example that works on the desktop version of the Timesheet screen. This example includes a button that merges rows that refer to the same issue. Figure 11-32 illustrates the function of this button.

383

Chapter 11 ■ Building Practical Application Features

Figure 11-32.  Merging duplicate issues To create this example, create a Detail screen for an engineer and include the related TimeTracking data collection. Add a button to your screen, and add the code that’s shown in Listing 11-21. Listing 11-21.  Querying an EntityCollection

384

Chapter 11 ■ Building Practical Application Features

The first part of this code groups the Timesheet records by issue and selects groups that contain more than one timesheet record. The second part of the code loops through the collection of grouped records, sums the total duration into the first record , and deletes the remaining records in the group . Notice how this code uses the Except operator to exclude the first record, and then uses the ForEach operator to loop through the duplicate records that require deletion.

Summary In this chapter, I covered practical features you can add to your application. This included how to add file-storage capabilities, how to integrate with mapping and GPS systems, and how to summarize data. I also described screen-design techniques that you can apply to various data structures. This included multiple-record selection, self-joined data, and tables that store a single row of data. To add file-storage capabilities to your application, I explained how to build screens to upload and download files from the database. For HTML clients, I showed you how to build a custom file upload control. To improve efficiency, this custom control uses the local file-processing capabilities within HTML5 browsers. If the client browser isn’t HTML5 compatible, the custom control automatically falls back to a more compatible but less efficient method. To enable users to retrieve files from the database, I explained how to add a file-download hyperlink to a screen. This hyperlink calls a server-side ASHX handler that uses the Server Application Context API to retrieve the file. For desktop client applications, you can use the Silverlight File Open and Save dialogs to enable users to upload and download files. It can be awkward to work with Silverlight file dialogs on LightSwitch screens. This is because you need to open the file dialog on the UI thread. Also, because of security restrictions, you can’t easily use the Silverlight dialogs on a desktop web application without writing additional custom control code. With desktop applications, you can write code that downloads and saves the file locally and opens the file with the registered application. This provides a simple way for users to open and view a file with just a single click of a button. To improve the workflow of your application and to allow users to carry out actions against multiple records, I showed you how to build a screen in an HTML client application that supports multiple-record selection. This technique builds a custom control that includes a checkbox against each item. The code stores the checked selections in a JavaScript array. You would create an ASHX handler that uses the Server Application Context API to carry out any data tasks you want to carry out. You would then create a button on your screen that calls the handler through a jQuery post and passes through the array data. In the table designer, you can build a data structure to model a hierarchy. In this chapter, I gave the example of a screen that enables users to manage the manager/subordinate relationship between engineers

385

Chapter 11 ■ Building Practical Application Features

in your database. To allow the assignment of subordinates, you would add a control. You would then create a button that adds the selected user to the subordinates collection of the managing engineer. An effective way to store application-configuration details is to store the details in a table. This table would contain just a single row; I described a screen-design technique you can use to read and write single rows to a table. This technique relies on code that runs when the screen opens. The code queries the database to see if a row exists in the table. If so, the code retrieves the record. Otherwise, the code creates a new record. Another useful screen-design technique is the ability to create sets of related data-picker controls. In this example, I showed you how to add an auto-complete box or modal window control that contains a list of department records. When a user selects a department, the code populates a second data control with a list of engineer records that are associated with the department. To filter the contents of an auto-complete box or modal window control by another control, you would bind the data source of the control to a parameterized query. You can then set the parameter value of this query to the value that the user selects from the first auto-complete box or modal window picker. Most modern mobile devices include GPS, and in HTML client applications you can write JavaScript code to add location awareness to your application. I showed you how to use the navigator.geolocation object to obtain the longitude and latitude of the device. I also showed you how to help users visualize data by adding Google maps onto LightSwitch screens. To add a map to a screen, you need to create a custom control with a DIV. You would then call JavaScript methods from the Google Maps API to fill the DIV with a map. Finally, I showed you code you can use to produce counts and sums of data. An important part of this exercise was to highlight where LightSwitch carries out the query. In desktop applications, LightSwitch carries out any aggregate functions you perform on navigation properties locally. If you carry out the same task against the underlying navigation property query, LightSwitch can delegate the query execution to SQL Server. You can use this technique to improve performance when generating counts and sums.

386

Chapter 12

Supporting Multiple Languages In today’s global economy, many businesses trade, operate, and carry out business across international boundaries. Such businesses can benefit greatly from applications that can support multiple languages. In this chapter, I’ll show you how to do the following: •

design applications in a way that can simplify the process of localization



localize HTML and desktop applications



localize server-side messages and objects

Localization is the process that adapts an application so as to support a range of languages and cultures. To demonstrate this process, this chapter will show you how to translate the Help Desk application into a language other than English.

Introduction In many cases, applications support just a single language. The chances of your needing to localize an application may seem remote. However, it’s still worth considering that one day you might need to localize your application. By considering localization issues at an early stage, you can more easily carry out this task when the need arises. At the most basic level, you can localize an application to support a different culture. An example of this might be the adaptation of a US application to support UK customers. The main bulk of this work would involve changing the spelling of words and reformatting date values to adhere to UK standards. Therefore, the process of localization doesn’t need to be as radical as supporting an entirely foreign language. The process of localizing an application involves abstracting the words and descriptions in your application into resource files. By using localization techniques, you can easily modify the words and labels that appear in your application. The localization technique isn’t limited to just foreign language support. For example, if you create an application that’s used by two different customers, you can modify the words and expressions that appear in the application by changing just the content of the resource files. The core code base for your application can remain the same for both customers. The need to support a foreign language might arise when companies merge, develop new trading partners, or are sold. These types of events can happen frequently in corporate environments. Having considered some of the reasons why you might need to localize an application, the good news is that there are simple steps you can follow to do so. If you’ve localized .NET applications before, the tasks involved will be familiar to you. Let’s review the high-level steps. First, you need to develop your application and screens in a way that’s easy to localize. Second, you need to provide foreign language translations for the English words in both your client and server projects. The remainder of this chapter will describe these two processes in further detail.

387

Chapter 12 ■ Supporting Multiple Languages

Supported Languages LightSwitch includes built-in dialogs and warning messages that are familiar to you. These are messages like “Cannot save – another user has modified the record” (Figure 12-1). LightSwitch provides translations for these system messages in 42 culture specific languages. You can see the list of supported languages by looking at the Default Language dialog in the General Properties of your application. The languages that LightSwitch supports include traditional Latin languages, in addition to right-to-left languages such as Chinese, Japanese, and Arabic.

Figure 12-1.  LightSwitch can display localized system messages Ideally, the target language of your application should be one of these 42 languages because this would allow you to build an application with matching UI and system message languages.

Preparing an Application for Localization There are various issues to consider when you build an application that you might want to localize. By keeping these considerations in mind, your job will be much simpler when that need arises. The first consideration is label length. When you translate words from one language to another, the length of the translated text will be different. For example, English words that you translate into German will often take up more space. Therefore, you should allow additional space to account for differences in word length when you design screens, and you should avoid setting static widths on labels. The best way to design a screen is to top-align labels (Figure 12-2). This provides space for the label text to grow or shrink. An extra benefit of top alignment is that it better supports the conversion of an English screen to a right-to-left language.

388

Chapter 12 ■ Supporting Multiple Languages

Figure 12-2.  You can more easily localize screens with top-aligned labels One other thing to avoid is hard-coded text in images. It takes more work to recreate images each time you localize an application into a different language than it does to localize plain text. Items that differ between cultures include address formats, date formats, and weights and measures. For example, there are subtle differences in street addresses, zip codes, and phone numbers between different countries. On a screen such as an address registration form, you can fix this issue by creating separate screens for each culture and opening the most suitable screen based on the locale of the user. Date formats differ between regions. With .NET, you can use built-in functions to format dates in long and short formats based on the location of the user. It’s good practice to use these features rather than hard code the date formats in your application. Different languages have different rules on pluralization. For certain languages, pluralization rules can be quite complicated. In English, you can pluralize a noun by adding (s) or (ies) to the end of a word. But in Polish, you would pluralize a noun by adding (i,y) to words that end in a vowel and (-e,y,i) to words that end in a consonant. This specific rule applies to two or more objects. For five or more objects, the rule is more complex. In this case, you need to remove the vowel from words that end with a vowel. To avoid writing complex pluralization code, you can simplify the translation task by phrasing messages in such a way as to avoid pluralization. For example, rather than display the confirmation message “You are about to delete 10 records. Do you wish to continue?”, you can use the phrase “Please confirm the delete operation (record count: 10).” The latter phrase saves you from needing to write code to determine the singular or plural form of the word record. Finally, don’t be tempted to localize everything. For example, make sure not to localize the currency symbol of a money field if the underlying purpose of the field is to store money values in a specific currency. Also, it’s often a good idea to avoid translating technical error messages, especially if the people who support your application are not fluent in the target language.

Localizing Server Objects To add support for multiple languages, you need to modify both the server and the client parts of your application. I’ll begin by describing the server tasks that are required in order to localize an application. A fundamental step is to localize the display names for the properties in your tables. Once you complete this task, every property label on all screens in both desktop and HTML client applications will display the localized value. Therefore, the benefit of this technique is that you can make quick progress by making a change in only a single place (the table).

389

Chapter 12 ■ Supporting Multiple Languages

The steps to localize table property display names are as follows. First, you need to create two or more resource files in the root folder of your Server project. The purpose of these resource files is to store the translated values. The first resource file is called service.resx. This file contains the default resource values. If, for example, a user attempts to view a French version of your web application, and your application doesn’t include French resources, your application would use the values that are stored in the service. resx file. The next step is to create localized resource files for the languages that you want to support. The names of these files should be in the format service.en-GB.resx. In this example, en-GB signifies a file that contains an English-language resource with a British culture. You can create culture-agnostic resource files by omitting the culture code. In this example, you could create a generic English resource file by naming your file service.en.resx. Supposing that your application includes a British English resource file and a generic English resource file, your application would use the British file for British users and fall back to the generic file for all other English users. These other users could include US, Australian, Canadian, and South African users. The second stage is to create client-side resource files in your desktop or HTML client projects. These resource files enable the client to localize UI elements such as screen titles and button captions. To localize a table property display name, you would open the table designer, select the Display Name setting for the property that you want to localize, and replace the English text with the syntax $(ResourceKey). In this instance, ResourceKey refers to a key value in the resource file. These key values can contain only letters and numbers, and not spaces. The actual resource value can contain any valid character. Once you carry out the substitutions on all the fields you want to localize, you can run your application. I’ll show you later how to change your language settings in order to test your application.

Translating Table Field Names To demonstrate how to localize a table, this section will show you how to translate the display names in the Engineer table from English to Spanish. The first step is to create the two service resource files. To do this, right-click your Server project and select the “Add ➤ New Item” option. When the Add New Item dialog appears, click the General container, add a new resource file, and name it service.resx. Now, add another resource file and name it service.es-ES.resx. The es-ES part of the filename indicates that this is a resource file for the Spanish language and Spanish culture. Edit these two resource files and enter the key-value pairs as shown in Figure 12-3.

Figure 12-3.  Contents of the Default and Spanish service resource files

390

Chapter 12 ■ Supporting Multiple Languages

For HTML client applications, you must create a client resource file. To do this, create a new folder called Resources in the Content folder of your HTML client project. Next, select the right-click “Add ➤ New Item” menu item and create a new file called client.lang-es-ES.resjson. Note that the Add New Item dialog for JavaScript projects excludes the option to add resjson files. Therefore, choose the “Text File” option instead. Once you have created this file, type the characters {} into the file. This is the syntax that defines an empty JSON object. There’s no need to provide any translation data at this stage. The critical step is to create a folder called Resources with at least one valid resjson file within it. If you fail to carry out this step, the HTML client will always show the default values that you define in the services.resx file and will never show the values that you define in the localized resx files. For desktop applications, you need to create at least two resource files in the root of your client project. Name the default file Client.resx and Spanish resource file Client.es-ES.resx. At this point, you can localize the table property display names. Open the Engineer table, select the first name property, open the properties sheet, and set the value of the display name property to $(Firstname), as shown in Figure 12-4. In this syntax, Firstname refers to the key value in the resource file. Repeat this process for the remaining properties in the table.

Figure 12-4.  Resourcing the Display Name setting of the Firstname property of a table A useful tip is that you can use this substitution technique for any of the property-sheet settings in the table designer. As Figure 12-5 illustrates, you can even use this technique to localize the display name values that you define in choice lists.

391

Chapter 12 ■ Supporting Multiple Languages

Figure 12-5.  Resourcing choice list items At this point, the localization task of the Engineer table is complete, and you can now run your application.

Testing a Localized Application To test your HTML client application, change the language setting of your browser and restart your application. In Internet Explorer, you can do this by clicking the Tools menu (or cog icon), selecting Internet Options, and clicking the Languages button in the General tab. For Windows 8 and above, you configure the language settings of IE through Windows Control Panel. The Languages button in the Internet Options dialog takes you to the correct place in Control Panel. To test a desktop application, use Windows Control Panel to change the language settings of your PC. When you restart your application, the screens will appear in the target language. Figure 12-6 shows a localized HTML client version of the application. As this screenshot shows, the table field names are now localized. However, some remaining parts of the application still require localization. This includes the screen title, the screen entries that appear in the navigation menu, and the caption that appears beneath the Add and Search buttons. I’ll show you how to localize these parts of your application later in this chapter.

392

Chapter 12 ■ Supporting Multiple Languages

Figure 12-6.  Example of a localized application in Spanish

Translating .NET Server Messages An important server task is to localize any messages that you create in .NET code. To give an example, let’s review how to translate one of the validation messages from earlier in this book. This message shows a warning when a user attempts to set the closed date of an issue to a value that’s earlier than the create date. The first step is to append the validation warning to the default service and Spanish resource files (Figure 12-7).

Figure 12-7.  Contents of the default and Spanish service resource files Once you add your localized error message, you can modify your validation logic to use the localized value, rather than the hard-coded value. The code that you need to use will depend on your client type.

Desktop Application Code In the case of a desktop application, select the ClosedDateTime property in the table designer, click the Custom Validation link in the properties sheet, and add the code that’s shown in Listing 12-1. Make sure to add the necessary references to the top of your code file.

393

Chapter 12 ■ Supporting Multiple Languages

Listing 12-1.  Localizing a validation message in a desktop application

The code in this listing retrieves the ValidateClosedDate value from the server resource file for the target language. The VB.NET syntax uses the methods in the My.Resources namespace to retrieve the resource value. If Visual Studio fails to find this namespace, open the properties sheet for both resource files and check that the Custom Tool and Custom Tool Namespace settings are set to ResXFileCodeGenerator and My.Resources respectively (Figure 12-8). Visual Studio can lose these settings if you copy and paste, or rename your RESX files.

394

Chapter 12 ■ Supporting Multiple Languages

Figure 12-8.  Custom Tool and Custom Tool Namespace settings For desktop applications, LightSwitch links the service resource files to the root of your client project. In this case, you will also need to set the Custom Tool and Custom Tool Namespace values for the RESX files that appear in your desktop client project. The fact that LightSwitch links the server resource files to your client project allows the client-side Silverlight code to access the resources that you define in your server resource files. The code in the C# listing uses reflection to retrieve the resource value. The reason I use reflection is because this technique works for both desktop and HTML client applications. The VB.NET listing can avoid reflection because the step that’s shown in Figure 12-8 exposes the service resources in the desktop client project via the My.Resources.Service accessor. It takes more effort to carry out the equivalent step in C# and, therefore, using reflection is the simpler option. At this point, you can run your application. If you switch your language setting to Spanish and attempt to set the closed date to a value that’s earlier than the create date, the application will display the localized error message as shown in Figure 12-9.

Figure 12-9.  A localized version of the validation error

■■Tip As the code in this section shows, it's a good idea to add a comment that shows the validation message in English. This can make your code more readable when you need to debug your application.

395

Chapter 12 ■ Supporting Multiple Languages

HTML Client Code If you apply the validation code from Listing 12-1 to an HTML client application, the validation message won’t appear in the correct language. As Figure 12-10 shows, if you set your browser to Spanish, the validation warning appears incorrectly in English while the rest of screen appears correctly in Spanish. The reason why the code works in desktop applications is because Silverlight executes the .NET code on the client. Therefore, the code can correctly determine the client language. In the case of a HTML client application, LightSwitch executes the validation code on the server because the HTML/JavaScript client cannot execute .NET code. Therefore, the validation code selects resources that match the language of the server rather than the language of the client. Therefore, you need to write some additional code to enable the validation code to work correctly in HTML client applications.

Figure 12-10.  The validation code doesn’t retrieve the correct resource in HTML client applications To localize the validation warnings for HTML client applications, open a table in the designer, select the SaveChanges_Executing method from the Write Code button, and add the code that’s shown in Listing 12-2.

396

Chapter 12 ■ Supporting Multiple Languages

Listing 12-2.  Localizing a validation message in an HTML client application

397

Chapter 12 ■ Supporting Multiple Languages

This code relies on methods in the system.web namespace to determine the language of the client. The UserLanguages collection returns an array of the languages the user has selected in the Internet Options section of their browser . The next line of code changes the UI culture and the culture of the thread that retrieves the resource. This ensures that the code retrieves the resource value in the language that matches the client. If you now run your application, the validation warnings will appear in the correct language. Because the server executes the code in this listing at the start of the Save pipeline process, all validation rules that refer to resources will apply the correct language. You don’t need to modify individual validation rules to apply this change. In the previous section, I demonstrated C# code that uses reflection to retrieve resource values. If your solution contains only an HTML client, you can avoid the use of reflection by using the shortcut accessors in the service namespace. One benefit of this technique is that the code editor provides IntelliSense suggestions for all the resource values that are available. For example, you can use the C# syntax Service.Service. ValidateClosedDate to retrieve the specific validation message that I showed you in the previous section.

Localizing HTML Client Resources After you have localized your Server project, the next step is to localize the messages and UI elements in your client project. These resources include screen titles, hard-coded pieces of screen text, menu-navigation items, and JavaScript alerts. LightSwitch utilizes client resource files to implement client-side localization, and I’ll now explain how to carry out this localization task.

Localizing Screen Titles and Menu Items Screen and menu titles are prominent parts of an application that require localization. In this section, I’ll demonstrate how to localize the screen title of the Browse Engineer screen. The first step is to append the localized values to a set of client resource files. Like the server localization task, the client project requires a default resource file. This file contains the resource values that LightSwitch uses when a user attempts to view your application in a language that you do not support. To add a default resource file, create a new file called client.lang-en.resjson in your Content\Resources folder. The language code of your default file must match the language of your web server. Unlike the server project, you can’t define a default resource

398

Chapter 12 ■ Supporting Multiple Languages

file by simply naming a file client.resjson. The correct way to define a default resource file is to name your file with a language and/or culture that matches the language and culture of your server. Because this example assumes that your target server is set to English, the name of the default resource file is named client.lang-en.resjson. After you create your default resource file, make sure to create a localized resource file in your Content\Resources folder. In our example, the name of the Spanish resource file would be client.lang-esES.resjson. Now, populate both files with the contents that are shown in Figure 12-11.

Figure 12-11.  Add the translated values to your client resource files To configure a screen to use the localized screen title value, replace the Display Name setting of your screen with code that references the localized version in your client resource file. Taking the example of the Browse Engineer screen, you would replace the Display Name setting with the value $(BrowseEngineers), as shown in Figure 12-12.

Figure 12-12.  Localizing the screen title You can use this same approach to localize the Display Name setting of the Add and Search buttons on this screen. When you now run your application, LightSwitch shows the localized screen title (Figure 12-13). Because LightSwitch uses the screen display names to build the navigation menu, this process also localizes the navigation menu and window title.

399

Chapter 12 ■ Supporting Multiple Languages

Figure 12-13.  Localized screen title, menu, and window titles at runtime

■■Caution  When you set a Display Name value to $(MyKeyValue), make sure there are no inadvertent trailing spaces after the end bracket. It’s easy to append trailing spaces by mistake when you copy and paste words between files. If there are trailing spaces, LightSwitch shows the key rather than the localized value, and you might struggle for a long time to find out why.

Localizing JavaScript Messages A typical application will include text values that are defined through JavaScript code. This might include screen text values or validation warnings. To demonstrate how to localize such pieces of text, let’s review how to localize the property value that shows the information message from Chapter 8. Like the previous example, the first step is to append localized values to your client resource files. This example relies on a key value called ValidationRequiredField that defines the string "(*) indicates required field". This example requires you to add a local string property called screenHeading to your Add/Edit Issue screen and to add a text control that binds to this property. Once you do this, select the created method from the Write Code button and add the code that’s shown in Listing 12-3. Listing 12-3.  Retrieving localized values from JavaScript code

400

Chapter 12 ■ Supporting Multiple Languages

As this code sample illustrates, you can replace any hard-coded string value with a call to the WinJS. Resources.getString method. This method returns the localized value based on the resource identifier that you supply to the method. In this case, the resource identifier is called ValidationRequiredField (as shown in Figure 12-11).

Localizing Dates and Numbers When you display date and numeric values with the default screen controls, LightSwitch automatically formats the data for the target locale. Therefore, you don’t need to carry out any additional work to format dates and numbers in the correct format. Figure 12-14 illustrates a screen in a Spanish browser that includes the date picker and text controls control. Notice how LightSwitch automatically configures the date picker to use the target locale.

Figure 12-14.  Automatically localized date and number values If you have code that applies custom formats using the momentjs or numeraljs libraries, you can store the localized formats in your resource files and use the JavaScript code from the previous section to retrieve the required format.

Localizing Desktop Apps In this section, I’ll show you how to localize the client section of a desktop application. To begin, I’ll show you how to localize the items that you define declaratively in the designer, and, afterward, I’ll show you how to localize .NET code.

Localizing Screen Titles and Menu Items You can localize the screen title and other settings that you define declaratively in the screen designer through a technique that’s very similar to the technique that you would use for an HTML client screen. The first step is to append the translated values to your client resource files, as shown in Figure 12-15. You should add a file called Client.resx to the root of your desktop client project. This file defines your default resource file. For our Spanish example, you would also need to create a file named Client.es-ES.resx and add it to the root of your desktop client project.

401

Chapter 12 ■ Supporting Multiple Languages

Figure 12-15.  Add the translated values to your client resource files The second step is to replace the Display Name setting of your screen with code that retrieves the localized version from the client resource file. Taking the example of an Editable Grid screen of engineer records, you would replace the Display Name value with the value $(EditableEngineerGrid), as shown in Figure 12-16.

Figure 12-16.  Localizing the screen and menu group display names LightSwitch uses the screen Display Name values to build the application navigation menu. Therefore, this process also localizes the navigation menu items. In desktop applications, the menu items are organized into navigation groups. You can use this same localization approach to set the navigation group display name (also shown in Figure 12-16). When you now run your application, LightSwitch shows the localized menu and screen title values (Figure 12-17).

402

Chapter 12 ■ Supporting Multiple Languages

Figure 12-17.  Localized screen title, menu, and window titles at runtime

Localizing Silverlight .NET Code Your screens might contain hard-coded strings in .NET code that require localization. To demonstrate how to localize strings that you define in .NET code, let’s localize the confirmation message code sample from Chapter 9. Just like in previous examples, the first step is to append the translated values to your client resource files, as shown in Figure 12-18. This screenshot includes translated values for both the confirmation message title and message itself.

Figure 12-18.  Add the translated values to your client resource files

403

Chapter 12 ■ Supporting Multiple Languages

Next, you replace the hard-coded text with code that retrieves the translated text from the resource file, as shown in Listing 12-4. This code looks similar to the earlier example where you resourced .NET server code. The main difference is that this code retrieves the localized values from the client resource file, rather than the server resource file. Unlike the earlier example, the C# code retrieves the localized values via the client accessor. The earlier example used reflection to enable the code to run on both the server and client tiers. Because this code only runs on the client, you can simplify the code by avoiding the use of reflection. Listing 12-4.  Localized version of displaying a message box

404

Chapter 12 ■ Supporting Multiple Languages

You can now run your screen; Figure 12-19 shows the appearance of the localized message box at runtime.

Figure 12-19.  Localized message-box text at runtime

Summary In this chapter, I showed you how to build applications that can support multiple languages. I described screen-design techniques that you can use to simplify localization, and I explained the steps that you need to carry out on the server and client to fully localize an application. There are certain design practices that can help simplify the development of a localized application. When you design a screen, you should try to top-align labels above textboxes, and you should try not to apply static widths or heights to controls. When you translate a word to a foreign language, the length will

405

Chapter 12 ■ Supporting Multiple Languages

often be different. If you follow this practice, you’ll face fewer problems with the alignment and sizing of controls. You can also reduce the amount of work you need to carry out by phrasing messages in a way that avoids pluralization. This saves you from having to write code to count the number of objects before choosing the correct spelling of the noun. You can localize a large part of your application by localizing the table property display names. Once you do this, any labels on screens that are based on the table will show the localized values. Another task you need to carry out in your Server project is to localize any messages that you generate in code, such as validation warnings. The technique with which to localize an application is to create resource files. Resource files contain key and name pair values. You create separate resource files for each language that you want to support. Within your application, you would replace each instance of an English phrase with code that looks up the translated version from the resource file. To localize table property display names and other server elements, create a file called service.resx in the root of your server project. Next, create resx files for each language you want to support in your application and name the file with the locale identifier after the word service. For example, you would name a Spanish resource file service.es-ES.resx. The next task is to populate the resource files with translated values that are keyed with an identifier. If you key the word Firstname with the identifier Firstname in the resource file, you would localize the display name of the table property by replacing the Display Name setting with the following syntax: $(Firstname). To complete the localization task, you need to localize resources that are specific to the front-end client. This includes screen names, button captions, and menu items. To localize UI elements, you need to create client resource files that contain key-name values. For an HTML client application, you would create a Content\Resource folder and create a file inside this folder called client.lang-en.resjson. The name of the Spanish resource file would be client.lang-es-ES.resjson. In the case of a desktop application, you would add the resource files to the root of your desktop project and name the default and Spanish files client.resx and client.es-ES.resx respectively. To replace a hard-coded value in the client (for example, a button caption), you would replace the Display Name setting with the code $(KeyValue), where KeyValue identifies the key value in the resource file. To retrieve localized values in server-side C# code, you would write code that uses a Resource Manager object. In VB.NET code, you can shortcut this by using the strongly typed resource accessors that you can find in the My.Resources namespace. In JavaScript, you would write code that calls the WinJS.Resources. getString method. To run an HTML client application in a different language, simply change the language setting of your browser. To run a desktop application in a different language, you would need to change your language setting through Windows Control Panel.

406

Chapter 13

Creating and Using Custom Controls The built-in desktop application controls that you’ve seen so far include labels, textboxes, auto-complete boxes, and data grids. If you can’t find a control that suits your needs, there’s no need to worry. With desktop applications, you can bind data items to custom Silverlight controls. This opens up many additional ways for users to interact with data. To further enhance your screens, you can build your own Silverlight custom controls or use controls that other people have developed. In this chapter, I’ll show you how to do the following: •

display data using custom controls



bind screen data to custom controls



develop your own Silverlight custom controls

To start off, I’ll describe the controls in the Silverlight SDK (Software Development Kit). I’ll show you how to apply a masked input control to a password-entry screen. Next, you’ll find out how to replace the auto-complete box with a ComboBox control. In the context of the Help Desk application, this control can better limit the choices that a user can select. I’ll also show you how to allow users to enter numeric data through the use of a slider control. Finally, I’ll show you how to build a custom duration control that can make it easier for users to enter time durations. This control will enable users to separately enter the hour and minute components of a time duration.

Using Custom Controls The easiest way to get started with custom controls is to use the UI controls in the Silverlight SDK. You’ll find these controls in the System.Windows.Controls namespace. Of course, you could choose to use other third-party Silverlight controls, but the advantage of directly using the controls in the Silverlight SDK is that it quickly opens up a whole host of additional UI controls that you can use, including: •

PasswordBox



WebBrowser



TreeView



RichTextBox



MediaElement



MultiScaleImage

407

Chapter 13 ■ Creating and Using Custom Controls



HyperLinkButton



ComboBox

A benefit of this technique is that you don’t need to create a separate project, and you don’t need to write very much code either. In this section, I’ll show you how to use the password box control from the Silverlight SDK. This control provides a masked password input box that replaces the characters that the user enters with a series of dots. I’ll show you how to apply this control to the Email Settings section of the Application Options screen, as shown in Figure 13-1.

Figure 13-1.  Password box control as it appears at runtime There are two parts to using a custom control. First, you need to specify a custom control for the data item that you want to use. Second, you need to write the code that binds the control to your underlying data. Here’s how to carry out both of these tasks.

Specifying a Custom Control To use the password box control, create a New Data screen for the AppOptions table (or reuse the AppOptionsEdit screen that you created in Chapter 11). Now, carry out the following steps in the screen designer: 1. Select the SMTPPassword data item and change the control type from a textbox to a custom control (Figure 13-2)

408

Chapter 13 ■ Creating and Using Custom Controls

Figure 13-2.  Selecting the password box control 2. Open the properties sheet and click the Change link. 3. When the Add Custom Control dialog appears, select System.Windows.Controls ➤ PasswordBox. If the password box control doesn’t appear, make sure to select the System.Windows DLL rather than one of the other DLLs (Figure 13-3).

Figure 13-3.  Make sure to choose the first System.Windows.Controls node

409

Chapter 13 ■ Creating and Using Custom Controls

Binding Data to Custom Controls Once you have configured a data item to use a custom control, the next step is to bind the control to your underlying data item. In this example, you need to bind the password control’s PasswordProperty to the AppOption entity’s password property. To do this, click the Write Code button, select the InitializeDataWorkspace method, and enter the code that’s shown in Listing 13-1. Listing 13-1.  Calling the SetBinding method

This code uses the FindControl method  to return an IContentItemProxy object. This object exposes a method called SetBinding. The purpose of this method is to data bind a control with a data source; it accepts three arguments. The first argument specifies the dependency property of the control to bind to. If you’re not sure what a dependency property is, just think of it as a property that you can bind data to. To help you choose the correct dependency property, use the code editor’s IntelliSense to view all the possible choices. You need to fully qualify the dependency property with the control type. In this example, the code prefixes the dependency property with the type System.Windows.Controls.PasswordBox. The second argument is the binding path. This is the most difficult part to get right, because this method requires you to supply a string value, and Visual Studio provides no guidance as to what you should enter. If you get this wrong, the control will not data bind correctly and LightSwitch won’t provide you with any compile or runtime errors. Therefore, this makes it difficult to trace the exact cause of a binding-path error. Developers often supply the binding path Value. This binding path binds your dependency property to the Data Context item that appears in the properties sheet (Figure 13-4). Table 13-1 shows other binding path values you can use.

410

Chapter 13 ■ Creating and Using Custom Controls

Figure 13-4. The Value data-binding path references the Data Context textbox Table 13-1.  Data-Binding Values

Binding Path

Data Binds to…

Value

The property that appears against the Data Context setting in the properties sheet

StringValue

The string-formatted version of the property that appears against the Data Context setting in the properties sheet

Details.Entity.Surname

Another property in the same entity (Surname, in this example)

Screen.localPropertyName

A local property on your screen

You could also choose to use the binding path StringValue rather than Value. StringValue reflects any specific formatting that the property applies, whereas Value simply returns the raw value. These property names (Value and StringValue) are public properties of the Microsoft.LightSwitch. Presentation.Implementation.ContentItem object. The final argument is the binding mode. You can supply one of three values: OneTime, OneWay, or TwoWay. When you set the binding mode to OneTime, the screen updates the control value when the control first binds to the data source. The OneWay setting configures the screen to update the control when the control binds to the data source and also whenever the source data changes afterward. The TwoWay option configures the control to update itself whenever a change in underlying data occurs, and to also update the underlying data source whenever a change in the control occurs. This completes the example, and you can now run your screen.

■■Tip Rather than using hard-coded binding paths, you could create a helper library that exposes a set of constants. The C# class would look something like this:  public static class ContentItemProperty  {   public const string Value = “Value”;   public const string StringValue = “StringValue”;   public const string DisplayName = “DisplayName”;   public const string Details = “Details”;   // etc.  } 411

Chapter 13 ■ Creating and Using Custom Controls

Binding Data Collections to Custom Control The password box example showed you how to bind a scalar value to a dependency property. In different circumstances, you might need to supply a custom control with a list of data or the results of a query. You would do this by binding a collection of data to a dependency property on the custom control; this example will show you how. To show you a practical illustration of how to apply this technique, this example will show you how to replace the priority auto-complete box on a new Issue screen. A disadvantage of the auto-complete box control is that users can type whatever text they choose, and if they enter invalid data, LightSwitch won’t notify them of the mistake until they attempt to save the record. To overcome this problem, I’ll show you how to use the combo box control. This control enables you to limit item selections to only those that the control shows (Figure 13-5).

Figure 13-5.  Illustration of combo box control

Designing the Screen The steps to use a combo box control are very similar to the steps you used to set up a password box control. However, there’s one additional task that’s required. LightSwitch doesn’t know how to populate your combo box control with data, so you need to add code that populates it with choice items. To create this example, add a New Data screen based on the Issue table. Name your screen CreateNewIssue. Select the Priority data item and change it from an auto-complete box to a custom control. From the properties sheet, click on the Change link and use the Add Custom Control dialog to select System. Windows.Controls ➤ ComboBox. Now click the Add Data Item button and create a new query called Priorities to returns all priorities. Figure 13-6 illustrates the screen layout. Click the Write Code button, select the screen’s Activated method, and enter the code that’s shown in Listing 13-2.

412

Chapter 13 ■ Creating and Using Custom Controls

Figure 13-6.  Configuring a data item to use a combo box control Listing 13-2.  Data binding a combo box control

413

Chapter 13 ■ Creating and Using Custom Controls

This code carries out two data-binding tasks with the SetBinding method. First, it populates the items that the combo box shows by binding the combo box’s ItemsSourceProperty to your Priorities query . The binding path to reference the Priorities query is Screen.Priorities . The next line of code sets the selected item in the combo box by binding the combo box’s SelectedItemsProperty to the Issue property’s Priority property . This completes the example, and you can now run your screen.

Converting Values When Data Binding Sometimes, the data type of the dependency property that you want to use might not match the data type of your data source. In this case, you’ll need to create a value converter to allow the control to correctly bind to the data source. To demonstrate this technique, I’ll show you how to use the Silverlight slider control on a screen. This screen binds to a table called Office (Figure 13-7). This table stores details about office locations and includes a property to store the building capacity of each location.

414

Chapter 13 ■ Creating and Using Custom Controls

Figure 13-7.  Office table schema The Office table defines the building capacity property as an integer, but the Silverlight slider control expects to bind to a number that’s of data type double. This mismatch means that in order to use the slider control, you will need to create a value converter that converts doubles to integers, and vice versa. To show you how to do this, this example creates a New Data Screen that allows users to create new offices and binds the building capacity property to a slider control. To carry out this example, here are the steps to follow: 1. Create a New Data screen based on the Office table and name it CreateNewOffice. 2. Change the BuildingCapacity data item from a textbox to a custom control. 3. In the properties sheet, click on the Change link. When the Add Custom Control dialog appears, select System.Windows.Controls ➤ Slider 4. Set the minimum width of the slider control to 300. It’s important to set this to a value other than auto; otherwise, LightSwitch shows only the Slider button, and not the Slider section that allows the user to make a selection. 5. Create a new columns layout beneath the main rows layout for your Office property. Set the label position of this group to Collapsed. 6. Drag your slider control into the columns layout. When you do this, make sure the Label Position setting is set to Left-aligned. 7. Add another BuildingCapacity data item into the columns layout and set the control type to be a label. Set the label position of the label to Collapsed. This label is designed to show the selected integer value when the user uses the slider control. Figure 13-8 shows how your screen now looks.

415

Chapter 13 ■ Creating and Using Custom Controls

Figure 13-8.  Screen layout in design view 8. In your client project, create a new folder called UserCode (if it doesn’t already exist) and add a new class called IntToDouble. 9. Add a reference to the PresentationFramework.dll assembly in the project where you added your IntToDouble class. The default location of this file on a 64-bit machine is (C:\Program Files (x86)\Reference Assemblies\Microsoft\ Framework\Silverlight\v5.0). Now, add the code that’s shown in Listing 13-3 to your IntToDouble class. Listing 13-3.  Value-converter code

416

Chapter 13 ■ Creating and Using Custom Controls

The IntToDouble class implements the IValueConverter interface  and contains the logic that carries out the data conversion. The Convert method  converts an integer value to a double, whereas the ConvertBack  method coverts a double value to an integer. Now, return to the screen designer, click the Write Code button, and select the screen’s Activated method. Add the code that’s shown in Listing 13-4.

417

Chapter 13 ■ Creating and Using Custom Controls

Listing 13-4.  Data-binding the slider control

You’re now ready to run your application; Figure 13-9 shows the appearance of the slider control at runtime.

Figure 13-9.  Illustration of slider control at runtime

418

Chapter 13 ■ Creating and Using Custom Controls

■■Tip  You can develop value converters to perform tasks that go beyond the simple task of converting a data type from one type to another. An imaginative example is the following. You could bind the background color of a textbox or text block control to an integer value. Your data could include a priority field that stores numbers, say, from 1 to 5. If the priority is set to 1, the background color should be green. If the value is 5, the priority should be red. A value converter would allow you to bind to the BackgroundProperty dependency property by converting the priority number into an object of type System.Drawing.Color.

Creating a Custom Silverlight Control The examples that you’ve seen so far have used the controls from the System.Windows.Controls namespace. If there isn’t a control here that suits your needs, and if you can’t find a third-party control that does what you need, another possibility is to create your own custom Silverlight control. The timesheet feature in the Help Desk application allows users to record the amount of time that has been spent on issues, expressed in minutes. To improve the presentation of this screen, create a custom control that users can use to view and edit time durations in hours and minutes (Figure 13-10).

Figure 13-10.  Duration control

Understanding Dependency Properties The duration control that we’ll create requires a dependency property to support the data binding between the control and the data source. Before we move on further, let’s take a closer look at what dependency properties are and how they work. Developers frequently use dependency properties in Silverlight and WPF (Windows Presentation Foundation) applications. They’re very similar to normal .NET properties but are more powerful. They use memory more efficiently, help support features like styles and animations, and also provide advanced features like coercion (I’ll explain what this is later), validation, and change notification. Change notification is particularly important because it alerts your LightSwitch screen whenever a user makes a change to a custom control value. Traditional .NET properties include two methods called get and set. In the vast majority of cases, these methods retrieve and set the value of a private field. Unlike traditional .NET properties, dependency properties don’t read their values from a private field. When you retrieve the value of a dependency property, .NET dynamically calculates the return value by using a process called dynamic value resolution. Let’s suppose that you write some code to retrieve the background color of a Silverlight textbox control. The background color might depend on various factors. It could inherit the setting from a parent control or it could be set through styles and themes. Furthermore, the control might be involved in an animation that constantly changes the background color. To retrieve the correct value, Silverlight searches for the background color in the following places in the order shown. It returns the first value that’s found.

419

Chapter 13 ■ Creating and Using Custom Controls

1. Animations 2. Binding Expression 3. Local Value 4. Styles 5. Property Value Inheritance 6. Default Value Dynamic value resolution begins by checking if the textbox is involved in an animation. If so, it returns the background color that the animation applies. If not, it checks whether the background color binds to an underlying data source. If so, dynamic value resolution returns the value from the data source. If there is no data binding in place, dynamic value resolution searches for a local value. A local value refers to the value that you explicitly set in code (for example, MyCtrl.BackColor = Colors.Green) or in XAML. If you’ve not set a local value, dynamic value resolution searches for a value that’s been set in a style or a template. If that doesn’t return a match, it’ll try to find the value that’s been set at the parent control. It’ll carry on searching up the tree of parent controls until it reaches the root control. And if a value isn’t found here, it returns the default value. The big benefit of this approach is that it’s highly efficient in terms of memory usage. Around 90% of the properties on a typical control stay at their initial value, so it’s inefficient to allocate memory by storing the value of every property on a control. Dependency properties only store the value of properties that have changed, which is a far more efficient approach. The local value of a dependency property isn’t stored in a field of your object, but rather in a dictionary of keys and values that the base class DependencyObject provides. The dictionary uses the property name as the key value for the dictionary entry. So, in summary, dependency properties don’t hold a concrete value. Their value can derive from many places—hence the name dependency property. They’re important in LightSwitch because if you want to bind screen data to a property on a custom control, that property must be a dependency property.

Creating a New Control and Dependency Property Now that we’ve covered what a dependency property is, let’s create our time duration custom control. This process requires you to create a Silverlight class library that contains a Silverlight user control. This Silverlight user control contains the textboxes and UI elements that define your custom control. To create a custom control, follow these steps: 1. Start Visual Studio. Click File ➤ New ➤ Project. When the New Project dialog appears, select the Silverlight Class Library template and name your project ApressControls. If you can’t find this template, use the search box that appears at the top of the New Project dialog. 2. Once your project opens, right-click your project in Solution Explorer and choose the right-click “Add ➤ New Item” option. 3. When the Add New Item dialog appears, choose Silverlight User Control and name your control DurationEditorInternal.xaml. 4. Drag two textbox controls from the toolbox into your user control. Name these controls HourTextbox and MinuteTextbox. Add two text block controls to the right of each textbox control and set the text attribute of the controls to “Hrs” and “Mins.” Listing 13-5 shows the XAML for the control. 5. Right-click an area of your XAML file, click on the “View Code” option, and add the .NET code that’s shown in Listing 13-6.

420

Chapter 13 ■ Creating and Using Custom Controls

Listing 13-5.  DurationEditorInternal.XAML Contents

Listing 13-5 shows the XAML for the VB version of the custom control. In this code, the name of the project is ApressControlsVB. If you recreate this example, make sure that your Class setting  matches the class name of your custom control. The line of code in  defines the textbox that allows users to enter the number of hours in the time duration. The text block control  shows the text “Hrs” to the right of the textbox. The next block of code repeats the same procedure with the minute component of the time duration. If you dragged the controls onto your control (as described in step 4), Visual Studio adds formatting attributes such as HorizontalAlignment, TextWrapping, VerticalAlignment, Width, and Height. I’ve omitted these attributes to make the code easier to read, but when you recreate this example, make sure to set the sizing and positioning details with the designer. If you don’t do this, all the controls will overlap each other.

421

Chapter 13 ■ Creating and Using Custom Controls

Listing 13-6.  Code-behind for DurationEditorInternal control

422

Chapter 13 ■ Creating and Using Custom Controls

423

Chapter 13 ■ Creating and Using Custom Controls

424

Chapter 13 ■ Creating and Using Custom Controls

425

Chapter 13 ■ Creating and Using Custom Controls

This code in this listing contains three distinct parts: 1. The first part of the code  registers the dependency property. I’ll explain exactly how this code works in the next section. 2. The code in  runs when underlying data value changes. This code updates the values of the hour and minute textboxes. 3. The code in  runs when the user updates the value of the hour or minute textboxes. It uses the CalculateDuration method to convert the duration that the user enters into minutes, and updates the dependency property.

Creating a Dependency Property Listing 13-6 includes the code that creates a dependency property. Here are the exact two tasks you need to carry out to create a dependency property: 1. Create a shared/static field of type DependencyProperty and call the Register method to create an instance of a DependencyProperty object. 2. Create a normal .NET property that “backs” your dependency property. This property stores the dependency property value by using the GetValue and SetValue methods that are inherited from DependencyObject. The DependencyProperty you just created in Step 1 acts as the key for the GetValue and SetValue methods. Let’s take a closer look at the code that registers your dependency property. To illustrate the arguments you need to supply, here’s the C# code from Listing 13-6.

This code defines a dependency property called DurationProperty. This name identifies your dependency property when you call the SetBinding method from your LightSwitch code. To adhere to .NET naming conventions, you should always name your dependency property with the suffix Property. The Register method accepts four arguments and returns an instance of a new dependency property object. There are four arguments that you need to supply to this method, as follows:

426



 The first argument specifies the .NET property that backs your dependency property. In this example, the .NET property is called Duration.



 The second argument specifies the data type of the .NET property.



 The third argument specifies the type that the dependency property belongs to.



 The fourth argument allows you to specify PropertyMetadata. I’ll explain what this does next.

Chapter 13 ■ Creating and Using Custom Controls

Specifying the Behavior of Dependency Properties The beauty of dependency properties is that you can specify default values, run code when the value of your dependency property changes, coerce values, and attach validation logic. The PropertyMetadata object is the key that makes all of this possible. As the line the follows shows, the PropertyMetadata constructor accepts four arguments. new PropertyMetadata(0, OnDurationPropertyChanged, null, null) 1. The first argument specifies the default value. The dependency property uses the default value only if it’s unable to determine a value elsewhere. Dynamic value resolution chooses the default value as the very last resort. Therefore, it chooses the default value if a value hasn’t been explicitly set, or if it isn’t able to find an inherited value. If you don’t want to set a default value, you can supply null (C#) or nothing (VB). 2. The second argument specifies a value-changed callback method. This is a method that runs each time your dependency property value changes. In this example, OnDurationPropertyChanged is the value-changed callback method. This method contains the logic that updates the values of the hour and minute textboxes. 3. The third argument specifies a coerce callback method. This allows you to run certain code in cases where a user attempts to set the value of your dependency property to a value that’s beyond what you intend your dependency property to store. For example, you could create a method that sets the duration value to 0 when a user attempts to supply a negative value. Your method could also set the duration to a predefined maximum value in instances when the user attempts to supply a value that is too large. The coerce callback method executes before the value-changed callback method. 4. The fourth argument specifies a validation callback method. The method that you specify here must return a Boolean result. This method enables you to write code to validate the value the user wants to set. If your method returns false, your dependency property will throw an ArgumentException.

Binding Dependency Properties to the Data Context At this point, you almost have a working custom control. Although you can now build and use the duration control in your applications, you would need to write code on your LightSwitch screen to call the SetBinding method, just like the code sample that I showed you in Listing 13-1. Let’s look at how to improve the duration control so that it binds directly to the associated data item on your LightSwitch screen. This improvement saves you from having to write extra code on your LightSwitch screen each time you use the duration control. If you were to bind DurationProperty to the associated data item on your LightSwitch screen, you would need to bind it with the binding path Value. The problem is that you have to specify the data-binding path in the XAML, but custom Silverlight controls don’t expose dependency properties in the XAML (as shown in Figure 13-11). The trick to get around this problem is to wrap a parent control around your custom control. This parent control acts as a conduit and exposes the XAML you can use to bind your control to the underlying screen value.

427

Chapter 13 ■ Creating and Using Custom Controls

Figure 13-11.  You can’t bind value to the data context To create this “wrapper,” follow these steps: 1. Right-click your project in Solution Explorer and choose the right-click “Add ➤ New Item” option. 2. When the Add New Item dialog appears, create a new Silverlight user control and name it DurationEditor.xaml. 3. Drag the DurationEditorInternal control from your toolbox onto your DurationEditor control. If the control doesn’t show on your toolbox, try rebuilding your project. Listing 13-7 shows how your XAML should look. Listing 13-7.  Duration Editor Control

In the code that’s shown, Visual Studio adds the local namespace  when you drag the DurationEditorInternal control onto your screen. If you recreate this example by typing the XAML from this book, make sure to enter the correct class name that corresponds to the name of your project. The definition of the DurationEditorInternal control  within the XAML allows you to data bind the “normal” Duration property by specifying the binding path Value. You can now build your ApressControls project. Save the output file (ApressControls.DLL) into a location to which you can refer later on.

428

Chapter 13 ■ Creating and Using Custom Controls

Adding the Duration Control to a Screen You can now add the duration control to a screen. To demonstrate the control, let’s review how to add it onto a New Data Entry screen that binds to the timesheet table. 1. Create a New Data Entry screen for the timesheet table. By default, LightSwitch will name this screen CreateNewTimesheet. 2. Change the DurationMins data item from a textbox to a custom control. 3. Open the properties sheet and click on the Change link. When the Add Custom Control dialog appears, click the Browse button and select the ApressControls. DLL file that you built in the previous section. Select the DurationEditor control from the Add Custom Control dialog. You can now run your application; Figure 13-12 shows the result of this screen at design time and runtime.

Figure 13-12.  Duration control

Calling Custom Control Methods via Dependency Properties Another practical use for creating dependency properties is to trigger methods in your custom controls. As an example, let’s look at the web browser control from the System.Windows.Controls namespace. As the name suggests, this control is designed to display web pages or HTML content on a screen. It’s important to note that this control works only in LightSwitch desktop applications and won’t work in browser applications. The web browser control includes a method called Navigate that allows you to supply a web address. When you call the Navigate method, the control displays the web page that you specify. If you add the web browser control to a LightSwitch screen, how exactly would you call Navigate method? There isn’t a simple way to call custom control methods from a LightSwitch screen. Therefore, a practical solution is to wrap the Navigate method in a dependency property. This would allow you to bind a web address to the web browser control and to automatically refresh the page that the web browser control shows whenever the underlying web address changes. To create the custom web browser control, carry out these steps: 1. Right-click your ApressControls project in Solution Explorer and choose the right-click ”Add ➤ New Item” option. 2. When the Add New Item dialog appears, choose Silverlight User Control and name your control WebBrowser.xaml. 3. Amend the XAML for your WebBrowser control as shown in Listing 13-8. 4. Right-click your XAML file, click on the “View Code” option, and add the .NET code that’s shown in Listing 13-9.

429

Chapter 13 ■ Creating and Using Custom Controls

Listing 13-8.  WebBrowser control custom control

Listing 13-9.  WebBrowser control code

430

Chapter 13 ■ Creating and Using Custom Controls

431

Chapter 13 ■ Creating and Using Custom Controls

Much of the code here is similar to the other samples in this chapter. The .NET code includes the same dependency property logic that I described earlier. This code creates a dependency property called URIProperty , basing it on a normal .NET property called uri . The dependency property's metadata specifies OnUriPropertyChanged as the value callback method. Whenever the underlying web-address data changes, the OnUriPropertyChanged method executes and calls the web browser control's Navigate method  to update the web page that the control shows. You can now build and use this custom control. The custom web browser control provides a useful tool for desktop applications, and in Chapter 16 you will see how you would use this control to show HTML reports on LightSwitch screens.

Calling Screen Code from a Custom Control As you might recall from Chapter 1, controls are simply views of the data and contain minimal business logic. In keeping with MVVM principles, it’s bad practice to build complex business logic into custom controls. A better approach is to define your business logic in screen methods and to call these methods from your custom controls. To demonstrate this technique, let’s look at how to create a stylized Save button. When the user clicks this button, it calls business logic on your LightSwitch screen, rather than logic on the control itself. To create this control, follow these steps: 1. Right-click your ApressControls project in Solution Explorer and choose the right-click “Add ➤ New Item” option. 2. When the Add New Item dialog appears, choose Silverlight User Control and create a control called SaveControl.xaml.

432

Chapter 13 ■ Creating and Using Custom Controls

3. Amend the XAML for your SaveControl control as shown in Listing 13-10. This XAML applies a green style to your control, but you could use the designer to apply a far more sophisticated look. 4. Right-click your project in Solution Explorer, choose the “Add Reference” option, and add references to the Microsoft.LightSwitch.Client.dll and Microsoft. LightSwitch.dll files. The default location of these files on a 64-bit machine is: C:\Program Files (x86)\Microsoft SDKs\LightSwitch\v5.0\Client\. 5. Right-click the contents of your SaveControl.xaml file, click on the “View Code” option, and add the .NET code that’s shown in Listing 13-11. Listing 13-10.  CustomButton code

433

Chapter 13 ■ Creating and Using Custom Controls

Listing 13-11.  Code to call a screen method called SaveData

434

Chapter 13 ■ Creating and Using Custom Controls

435

Chapter 13 ■ Creating and Using Custom Controls

When a user clicks on the custom button, the application executes the CustomButton_Click method . The first part of this code disables the button to prevent users from clicking it multiple times . All custom controls data bind to objects that implement the IContentItem interface. This object allows you to access the control’s parent screen via the Screen member . The next block of code calls the method on your LightSwitch screen. This could be a long-running data operation, so you’ll need to execute this code on the screen’s logic thread. This prevents the process from locking up the UI and leaving your application unresponsive . The next line of code accesses a screen command called SaveData via the screens’s Details.Commands collection and runs the command by calling its Execute method . If the command succeeds or fails, the code in the finally block re-enables the custom button. The code that re-enables the button must run on the UI thread because it performs logic that modifies the UI. Because the current code block executes on the screen-logic thread, the SetEnabled method re-enables the button on the correct thread . To show you how to use this control on a screen, let’s look at how to add it to the Timesheet screen that we created earlier. To do this, you’ll need to carry out the following steps: 1. Open the Create New Timesheet screen that you created earlier in this chapter. 2. Click on the Add Data Item button and create a new method called SaveData. 3. Click on the Add Data Item button and create a local property of data type String and name it SaveDataButton. Uncheck the “Is Required” checkbox. 4. Add the SaveDataButton property onto your screen and change the control type from a textbox to a custom control. 5. From the properties sheet for the SaveDataButton property, click the Change link. When the Add Custom Control dialog appears, click the Browse button and select your ApressControls.DLL file. When the Add Custom Control dialog appears, choose the CustomButton control. Set the label style for the data item to collapsed. 6. Right-click the SaveData method in the screen member list and click on the “Edit Execute Method” option. Enter the code that’s shown in Listing 13-12.

436

Chapter 13 ■ Creating and Using Custom Controls

Figure 13-13.  Custom Button screen design view Listing 13-12.  Screen code that is called by the Custom button

An important point is that you must create the screen method that you want to call by using the Add Data Item dialog box in the screen designer. If you try to call a method that you manually add to your code file, your custom control won’t find the method in the screen’s Details.Commands collection, and your code won’t work. The name of the method that’s shown in Listing 13-12 is called SaveData_Execute. But when you access commands via the screen’s Details.Commands collection, you would refer to the method without the _Execute suffix (as shown in Listing 13-11, ) You can now run your application; Figure 13-14 shows how your screen now looks.

437

Chapter 13 ■ Creating and Using Custom Controls

Figure 13-14.  Custom button control The custom control that we’ve created here contains just a button; the purpose of this example is to show you how to call screen code from a custom control. More complex custom controls might feature multiple UI elements, and a button (or some other event) to call screen code would make up part of the custom control. In this example, you’ll notice how we bind this control to a local string property (the SaveDataButton property). In Chapter 19, I’ll show you how to adapt this code sample to enable you to bind directly to your screen command.

■■Tip In this example, we’ve hard-coded the name of the command (SaveData) into our custom control. You can make this example more reusable by passing the command name into the custom control, rather than hard-coding it. You could do this by creating a dependency property. This would allow you to use the data-binding mechanisms that you’ve seen to bind your custom control to the command objects in LightSwitch.

Summary LightSwitch allows you to visualize your data by using Silverlight controls. This frees you from using only the standard set of controls that LightSwitch provides. For example, you could write your own controls to show data with charts, slider controls, or other, more sophisticated input-entry controls. One of the simplest ways to enrich your application is to use the controls in the System.Windows. Controls namespace. The controls from this assembly include the combo box, password, and web browser controls. To apply a custom control to a data item on your screen, use the data item’s drop-down box to set the control type to “Custom Control.” If you apply a control directly from the System.Windows.Controls namespace, you need to write code that binds it to your data context by calling the SetBinding method. This method requires you to supply a dependency property and a binding path. To bind a dependency property to the data-item value, you would use the binding path of Value. Other binding path expressions enable you bind your control to other entities, properties, or local screen properties. If you want to bind screen data to a property on a custom control, that property must be a dependency property. Unlike normal properties, dependency properties don’t hold a concrete value. Their value can derive from many places, and the benefit of this is that it uses memory more efficiently. If you create your own custom control, you’ll need to create a dependency property if you want to consume LightSwitch data from within that custom control.

438

Chapter 13 ■ Creating and Using Custom Controls

To create a dependency property, you would define a dependency property object and instantiate it by calling the Register method. You’ll need to define a normal .NET property that backs your dependency property. This property stores your dependency property value in a dictionary that the base class DependencyObject object provides. If you want to use a custom control that you create yourself and don’t want to write SetBinding code for each instance of your control, you can wrap your control in a parent control and set the data binding in the XAML for your parent control. Another reason to use dependency properties is to call methods within your custom control. To demonstrate this, I showed you how to wrap the web browser control’s navigate method inside a dependency property. This enables the control to update the content that it shows whenever the underlying data changes. If you want to bind a data item to a dependency property when the data type of the data item and dependency property don’t match, you can write a value converter. I showed you how to write a value converter that converts integers to doubles, and vice versa. Finally, you learned how to call a screen method from a custom control. The custom control code uses the screen’s Details.Commands collection to find the screen method. Once it obtains a reference to the screen method, it can execute the code in the method.

439

Part V

Extending the Reach of Your Data

Chapter 14

Optimizing Data Connectivity with RIA Services With LightSwitch, you can connect to a wide range of data sources. However, if you can’t natively connect to the data source of your choice, you can still consume the data by writing a WCF RIA service (Windows Communication Foundation Rich Internet Application Service). In this chapter, you’ll learn how to do the following: •

create an RIA service to retrieve and update data



consume an RIA service from your LightSwitch application



call SQL Server stored procedures

You can create a custom RIA service to connect to data sources that are not well supported. These data sources include non-relational data or data sources that don’t have an Entity Framework data provider. For example, you could create an RIA service to expose the data within XML files, a Windows event log, or even the IIS log file on the server. RIA Services also allows you to create aggregated views of data, or to create views that join multiple database tables. An aggregate view could provide counts, sums, averages, or totals of a group of data. This can help you create views of your data for statistical or reporting purposes. In this chapter, you’ll find out how to create an RIA service to improve the performance of the Help Desk application. You’ll learn how to perform data operations and also how to call an SQL server stored procedure to delete engineer records.

The History behind RIA Services To begin this chapter, let’s look at a brief history of RIA Services. Microsoft first announced RIA Services in 2009. In a nutshell, RIA Services allows Silverlight clients to call code that runs on the server. Typically, this server-side code carries out data access, but it can also carry out other tasks such as validation. RIA Services first became available in Visual Studio 2010 (Service Pack 1) and was well supported in Visual Studio 2012. In 2013, Microsoft donated the source code for RIA Services to an open-source foundation, and the ongoing development of this product now continues through an open-source model. The open-source version is called Open RIA Services, and you can download it and find out more from the following website: http://openriaservices.codeplex.com/.

443

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

As part of the transition to an open-source model, Microsoft removed several of the tools that supported RIA Services from Visual Studio 2013. Specifically, Microsoft removed a wizard you could use to build domain service classes, a Business Application Project template, and other toolbox items. Developers that want to use these features can continue to do so by using Open RIA Services and installing the tooling add-ons you can download from the website. Microsoft still supports the version of RIA Services from Visual Studio 2013 and earlier. This version supports the majority of the use-case scenarios that you’ll encounter when you develop a LightSwitch solution. You can use this version by referencing the correct DLLs; this is the approach that I’ll describe in this chapter. It’s useful to understand this background, because if you research this topic further, you’ll find documents on the web that refer to Visual Studio tools and Windows that no longer exist in Visual Studio 2015.

Creating an RIA Services Project Let’s now examine the steps to build an RIA service that you can use in a LightSwitch project. This process consists of the following four steps: 1. Create a class library project. 2. Write a class that represents your entity. 3. Add a domain service class. 4. Add data-access code to your domain service class. Throughout the remainder of this chapter, I’ll cover these steps in greater detail. The example I’ll use in this chapter focuses on performance. To illustrate a typical performance bottleneck, let’s examine the engineer table. This table stores engineer details and a photo. Let’s suppose you add a screen that shows a list of engineer first names and surnames. Although you don’t show the Photo field on this screen, the LightSwitch client still fetches the photo data from the server. This is because the server can only return entity sets to the client, and entity sets can’t exclude fields. If your average photo size is 500 KB, and you retain the default page size of 45 records (for desktop applications), you could incur an additional 20 MB of data transfer between the client and server each time the page loads. By creating an RIA service that excludes the photo data, you can build a screen that performs more quickly.

■■Note An RIA service is one way to solve this problem. In practice, you’ll find that it’s quicker to split the employee photo data into a separate table. In this chapter, I’ll show you how to address this exact performance problem. I’ll also show you how an RIA service can improve the performance of a computed column. Let’s imagine an Engineer screen that shows a count of issues for each engineer (Figure 14-1).

444

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

Figure 14-1.  Engineer Management screen that shows a count of issues As a result of the high number of records in the system, this screen performs poorly—LightSwitch needs to retrieve every issue record for each engineer just to calculate the count (you’ll find the computed column code in Chapter 2). We can address this type of performance problem by retrieving the count with more-optimal SQL and exposing the results through an RIA service.

Creating a New Project To create an RIA service, open Visual Studio and create a new project with the Class Library template. Name your project HelpDeskDataService. Next, add references to the assemblies that are shown next. You can do this by right-clicking the References node in Solution Explorer and clicking the “Add Reference” menu item. •

System.ServiceModel.DomainServices.Server



System.ServiceModel.DomainServices.Hosting



System.ComponentModel.DataAnnotations

Creating an Entity Class Your RIA service project needs a class that represents an Engineer entity. This class doesn’t need to contain every column in the engineer table. As I mentioned earlier, an ideal way to optimize performance is to return just a subset of columns. In your project, create an EngineerRecord class and add the code that’s shown in Listing 14-1.

445

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

Listing 14-1.  Entity class for an engineer record

446

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

This code shows how you must decorate the primary-key property (ID) with the key attribute and set the Editable attribute to false . LightSwitch uses these attributes to prevent users from editing your engineer’s ID property.

447

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

The Required attribute  indicates that the property can’t be null or empty. If a user fails to enter any of the required properties, LightSwitch triggers its built-in validation and prevents the user from saving the record. The StringLength attribute  allows you to specify the maximum length of a property. LightSwitch’s built-in validation uses this value to prevent users from entering text that exceeds the maximum length that you specify. It’s important to apply the StringLength and Required attributes to stop users from entering invalid data. In addition to the attributes that I’ve shown you here, you can also define relationships and navigation properties by setting similar attributes. If you do this, LightSwitch will recognize the relationships and navigation properties that you specify when you attach to your RIA service.

■■Tip The code used to create a custom data-source extension looks very similar to the code that’s shown in this section. You can refer to Chapter 20 if you want to see an example of how to create an entity class that includes navigation properties.

Creating a Domain Service Class The next step is to create a domain service class. To do this, right-click your project and choose the option to add a new class. Name your class EngineerDataService. Once you do this, you can begin to write your data-access logic.

Retrieving Data To retrieve the engineer records from the database, this code uses ADO.NET. Listing 14-2 shows the data-access code that you will need to add to your class. To support the function that retrieves the database connection string, you need to add a reference to the System.Configuration assembly. As before, you can do this by right-clicking the references node and clicking the “Add Reference” menu item.

448

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

Listing 14-2.  Domain service code for retrieving records

449

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

450

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

451

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

452

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

The GetEngineerData method  returns the engineer data. Notice how the attribute Query(IsDefault=true)  decorates this method. LightSwitch uses this attribute to determine the method it should call in order to retrieve a collection of data. If you don’t decorate a method with this attribute, and don’t decorate any properties with the Key attribute, LightSwitch won’t allow you to add the entity set to your application. This code uses ADO.NET to connect to your SQL data source. If you were writing an RIA service to connect to a non-supported data source, you would adapt the code in this method to use a different data-access mechanism. The data-access code here creates an SqlConnection object  and uses an SqlCommand object to specify the SQL command to execute. The SQL that this method specifies  produces the issue count much more efficiently than does the native LightSwitch computed column code.

Retrieving a Connection String from web.config It is good practice to store your database connection strings in the web.config file of your LightSwitch application. By doing this, you can more easily modify your database connection string after you deploy your application. When you connect to an RIA service at design time, LightSwitch displays a prompt that you can use to enter a connection string (you’ll see this dialog later in the “Consuming Your RIA Service” section). LightSwitch saves your connection string in the ConnectionStrings section of your web.config file, and it keys the entry with the fully qualified name of your class. You can obtain the connection string value in your RIA service code by using the methods in the ConfigurationManager namespace, as shown here: VB: ConfigurationManager.ConnectionStrings(Me.[GetType]().FullName)  .ConnectionString   C#: ConfigurationManager.ConnectionStrings[this.GetType().FullName]  .ConnectionString; In practice, you might also want to write some additional error-checking code to make sure that the connection-string setting exists, and that it isn’t null or empty. Also note how the code decorates the name of the domain service class with the description attribute. LightSwitch shows this description when you attach to the RIA service from the Add Data Source wizard.

Updating Data In addition to retrieving data, you can use an RIA service to add and update records in a database. To extend your RIA service to support the addition and amendment of engineer records, add the code that’s shown in Listing 14-3.

453

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

Listing 14-3.  Updating and inserting data

454

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

455

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

This RIA service uses the UpdateEngineerData  and InsertEngineerData  methods to insert and update data. LightSwitch understands that these are the methods it needs to call to insert and update data through the presence of the Insert and Update prefixes in the method names. There isn’t any more that you need to do to indicate that these methods are responsible for inserting or updating data. The insert and update methods use ADO.NET code to update the database. This code uses named parameters to prevent rogue users from carrying out SQL injection attacks. The SQL command within the InsertEngineerData method includes an additional command that selects @@Identity . This command retrieves the auto-generated identity value that SQL Server assigns to the newly added record. This code then executes the command by calling the command’s ExecuteScalar method. This allows it to retrieve the ID value of the newly added engineer entity, which it then assigns to the engineer’s ID property (). This allows your user to see the ID number of the record onscreen immediately following a save operation.

Calling SQL Stored Procedures If you work with existing SQL Server databases, the ability to call SQL Server stored procedures can be very useful. For security reasons, it’s not uncommon for database administrators to block developers from accessing tables directly. The only way that you can often work with an SQL database that you don’t own is to retrieve data through views and update data through stored procedures. Another scenario for using stored procedures is to improve performance. For certain data-intensive tasks, it can be more efficient to perform the work at the database through a stored procedure rather than through the application pulling large amounts of data into the business logic layer.

456

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

To demonstrate, I’ll show you how to extend the domain service to support the deletion of engineers through a stored procedure. In this scenario, using a stored procedure will also help you perform an additional piece of functionality. It allows you to cascade-delete all related issue records when a user deletes an engineer. Although LightSwitch provides basic cascade-delete functionality, there are some challenges that you need to overcome to make it work with our sample application. First, the engineer table includes a self-relationship that stores the manager for each engineer. Self-join navigation properties don’t include the ability to disassociate related records on deletion. So, if the engineer that you want to delete is the manager of other engineers, you can’t automatically set the manager field for all subordinate engineers to null. Second, there are two relationships between the engineer and issue tables. For each issue, an engineer can be assigned to the issue or to the engineer that closes the issue. LightSwitch only allows you to specify a single cascade-delete rule on any pair of tables, so you would need to manually carry out the cascade deletion. Figure 14-2 illustrates these issues.

Figure 14-2.  Cascade-delete issues When you cascade-delete records, it’s also important to consider performance. During this process, the Save pipeline loads the records that it needs to cascade-delete. So, in this example, LightSwitch will load all issue records that are related to the engineer before deleting the issues and the engineer. For each issue record that LightSwitch deletes, it needs to load the issue response and document records in order to carry out the cascade-delete rules that are defined on the issue table. And because each issue-document record can be large, there’ll be a noticeable delay in performance. In this situation, a stored procedure provides an efficient alternative, because it bypasses the need to load data prior to deletion. To carry out this example, you’ll need to create a stored procedure in your database. To define a stored procedure in your development database, you can use the Server Explorer tool in Visual Studio. The first step is to build and run your application. This attaches your database in LocalDB. Next, you can use the rightclick menu item in Server Explorer to add a connection to your database. When the Add Connection dialog opens, enter the server name (localdb)\MSSQLLocalDB and use the drop-down to select your database (Figure 14-3). Once you add your connection, you can use the right-click context menu on the Stored Procedures node to define a new stored procedure in your database.

457

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

Figure 14-3.  Connecting to the Intrinsic database in Server Explorer Listing 14-4 shows the stored procedure code that carries out the deletion. Note that the table column names in your underlying SQL database may vary from the names that are shown in this listing. You can use the Tables node in Server Explorer to work out the exact column names to use in your stored procedure code.

458

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

Listing 14-4.  T-SQL definition of the DeleteEngineer stored procedure

After you create your stored procedure, add the delete method to your domain service, as shown in Listing 14-5.

459

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

Listing 14-5.  Deleting records

Just like with the update and insert methods, you need to prefix the delete method with the word delete. This indicates that the method is responsible for deleting the engineer entity.

460

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

This ADO.NET code is similar to the code I showed you earlier. An important difference is that you must set the CommandType property of the SqlCommand object to StoredProcedure . Your SQL command will not run correctly if don’t do this. This completes everything that you need in order for your RIA service to work. Now, build your project and make a note of the output DLL file that your project produces.

Consuming Your RIA Service Once you build your RIA service, you can easily consume it from your LightSwitch application. To do this, right-click your SQL Server project, select the “Add Data Source” menu item, and choose the WCF RIA Service option. When the Choose a WCF RIA Service dialog appears (Figure 14-4), click the Add Reference button. When the Reference Manager dialog appears, click on the Browse button and select the HelpDeskDataService.dll file that you built earlier.

Figure 14-4.  Attaching a WCF RIA service

461

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

The next step prompts you to select the entities and properties you want to use, just as you would for any other data source (Figure 14-5). You can specify a name for your data source in this dialog. This is the name that identifies your data source in Solution Explorer and the name that you use to access the data source in code.

Figure 14-5.  Choosing the entities to include This dialog also contains a text box you can use to enter a connection string (Figure 14-5). Notice how the text box includes the placeholder text Enter the connection string to the HelpDesk Database. This help text comes from the description attribute of your domain service class, which was shown in Listing 14-2. To complete the addition of your RIA service data source, click the Finish button. You can now recreate the Engineer screen using your RIA service. You’ll find that this new screen performs much more quickly than the previous screen.

462

Chapter 14 ■ Optimizing Data Connectivity with RIA Services

Summary You can use RIA Services to perform data-related tasks that LightSwitch doesn’t natively support. For instance, you could write an RIA service to connect to data within a Microsoft FoxPro or Access database, or even from a non-relational data source. You can use RIA Services to create views of your data. These could be aggregated views that contain counts, sums, and averages of your data, or might even be a view that contains joined-up data from multiple tables. Instead of joining data, you could alternatively create a view that returns a subset of columns from a table. This technique can help optimize the performance of your application, particularly if you have a table that contains records with large rows (a table that contains images, for example). To create an RIA service, you need to create a class library project with a domain service class. Within this library project, you need to create a class that represents your entity. If you want to return an Engineer entity, for example, you’ll need to create an engineer class and include properties that represent the employee ID, surname, first name, and so on. You must decorate the property that acts as the primary key with the key attribute. If you don’t specify a key property, LightSwitch won’t allow you to import your entity. Every RIA service must contain a method that returns a collection of data. The return value from this method must be an object that implements the IQueryable interface. For LightSwitch to recognize this as the method that returns all entities, you must decorate the method with the attribute Query(IsDefault:=True). To update data, you would create methods that you prefix with Insert, Update, or Delete. These methods must include a parameter to accept an instance of your entity. You can store the database connection string that your RIA service uses in your web.config file. This allows you to change the setting after you deploy your application. You can easily set the connection string when you attach your RIA service, and retrieve it in code by using the methods in the ConfigurationManager namespace. Once you create an RIA service, you can consume it from your LightSwitch application by attaching to it through the Attach Data Source wizard, just as you would for any other data source.

463

Chapter 15

Sharing Data with OData With LightSwitch, there are many ways for you to connect to external data. You can do this through the Add Data Source dialog, and for non-standard data sources, you can create your own RIA service. OData (Open Data Protocol) provides yet another choice. While other data-access methods allow you to connect to data sources, the added benefit of OData is that you can use it to view and update LightSwitch data from applications outside of LightSwitch. In this chapter, I’ll show you how to do the following: •

connect to third-party data by using OData



share your LightSwitch data with other applications



update LightSwitch data from outside of LightSwitch

This chapter will extend the Help Desk application by combining office location details with travel-advice data that comes from an Internet data source. I’ll show you how to connect to LightSwitch data from an Excel spreadsheet, and also how to build an external ASP.NET website that users can utilize to update issue records.

Introduction OData is an open standard that provides a common way to retrieve and update data via the web. A common standard makes it easier for you to connect to external data because it saves you from having to learn a separate data-access API for each data type you want to access. For example, SAP (the enterprise resource-planning software product) publishes its data via OData. The great thing is that you can display SAP data inside LightSwitch without your having to learn a complicated new API. If you want to connect to LightSwitch data through an external application, there are many languages and platforms that you can use, including Java, PHP, Ruby, JavaScript, and many more. In the first section, you’ll learn to attach to an OData data source. Later in the book, you’ll find out how to attach to LightSwitch data from Excel and .NET.

Using External Data Sources By building a LightSwitch application that connects to external data sources with OData, you can consolidate the vast amounts of disparate data that organizations own. Microsoft products that support OData include SharePoint 2010, Microsoft Dynamics CRM 2011, and SQL Server Reporting Services 2012. If your company uses any of these products, you can use LightSwitch to connect to the data that these applications hold. In addition to accessing OData data sources from within your organization, there are plenty of third-party and external data sources that you can use. I’ll now show you how to find public data sources that you can incorporate into your LightSwitch applications.

465

Chapter 15 ■ Sharing Data with OData

Finding Third-Party Data Sources to Use A great place to find public data sources is the EcoSystem page on the official OData website (http://www.odata.org/ecosystem). Here, you’ll find a list of third-party OData providers that includes EBay, Netflix, and Windows Live. Another great place is the Data Services section of the Azure Marketplace (https://datamarket.azure.com/ browse/data). Here, you’ll find many data sources, some of which are free, and others that must be paid for. To demonstrate how to consume an OData data source, I’ll now show you how to connect to a travel-advisory service that the UK Foreign and Commonwealth Service provides. This enables the Help Desk application to associate travel-advice information with the office locations that are stored in your application. You can find this service by visiting http://datamarket.azure.com/dataset/uk.gov/ traveladvisoryservice. To use this service, you’ll need to create an account on the Windows Azure Marketplace. Once you do this, the next step is to click on the Sign Up button that you’ll find on the Travel Advisory Service’s web page (at the time of writing, it’s free to sign up). Once you sign up for a Marketplace service, you can use the website’s “Explore this Dataset” option to preview the data that the service offers (see Figure 15-1).

Figure 15-1.  Azure Marketplace

Determining Connection Settings To connect to an OData data source, you need to know the web address that identifies the data source as well as any authentication details that the service requires. The Travel Advisory Service displays these details in the Details tab of its web page. The OData address that you’ll need is labeled “Service root URL,” as shown in Figure 15-2.

466

Chapter 15 ■ Sharing Data with OData

Figure 15-2.  Finding the address of an OData source in the Azure Marketplace All the services from the Azure Marketplace require authentication. To find out your credentials, go to the My Account section of the Windows Azure Marketplace and make a note of the Customer ID and Account Key settings (Figure 15-3). You’ll need these details to authenticate to this service from LightSwitch.

Figure 15-3.  Determining your authentication credentials

■■Caution  Because certain elements of the Windows Azure Marketplace are chargeable, you should protect your account keys in the same way as you would protect a credit card number.

467

Chapter 15 ■ Sharing Data with OData

Connecting to an OData Data Source To connect to an OData data source from LightSwitch, right-click Solution Explorer and select the “Add Data Source” menu item to open the Attach Data Source wizard. When the wizard opens, select the OData option. In the Enter Connection Information page, enter your OData URL into the “Specify the OData service endpoint” text box (Figure 15-4). In the travel-advisory example, the Customer ID is your username and the Primary Account Key is your password.

Figure 15-4.  Attaching to the travel advisory service By default, LightSwitch checks the “Attach to this data source as read-only” checkbox. This is because OData data sources are more likely to be non-updatable. This option disables the insert, update, and delete commands on screens and also prevents you from updating the data source through code. The next step in the wizard prompts you to select the entities that you want to use in your application (Figure 15-5). Once you complete the wizard, you can use the data source just as you would any other data source. Remember that you can also add relationships between entities in different data sources. Figure 15-6 shows the appearance of this data when you include it on a screen that includes department data.

468

Chapter 15 ■ Sharing Data with OData

Figure 15-5.  Choosing your entities

Figure 15-6.  A screen that uses the OData data source

Understanding Default Data-Source Options OData feeds from different sources behave differently. In the Foreign and Commonwealth Office (FCO) example, the FCO might not implement all the underlying OData query operators that LightSwitch supports. For example, some OData data sources don’t support paging, sorting, or certain kinds of query filters. To stop your application from breaking when LightSwitch tries to do something that your data source doesn’t support, LightSwitch applies application options that are more restrictive than normal. First, it switches off searching by setting the Is Searchable option to false at the entity level. Any collections of

469

Chapter 15 ■ Sharing Data with OData

data that you add to a screen will also have their Support Search settings set to false. If you later discover that your OData data source supports searching, you can manually enable the setting in the table designer’s property sheet. However, you should be aware that this can have a negative impact on performance. To further help performance, LightSwitch disables eager loading if your screen contains multiple related tables from an OData data source. Finally, LightSwitch also disables pagination on data grids and data lists if it isn’t able to request an individual page of data or count how many pages of data there are.

Exposing Your LightSwitch Data Via OData With OData, you can very easily attach to LightSwitch data from external applications. LightSwitch publishes your data through OData feeds, and in this section I’ll show you how it works.

Finding Your Application’s Endpoint URL LightSwitch creates service endpoints for each data source in your application. You can access these endpoints in a web browser by entering the root URL for your application followed by the data-source name with a .SVC extension, followed by the name of your entity set. Figure 15-7 shows some example URLs.

Figure 15-7.  OData endpoint URLs To see the data that an OData endpoint returns, start up a LightSwitch web application and make note of the root URL—it’ll look something like this: http://localhost:41155/. Now, open a new browser tab and enter http://localhost:41155/ApplicationData.svc/Engineers into the address bar. This returns the raw data, as shown in Figure 15-8.

470

Chapter 15 ■ Sharing Data with OData

Figure 15-8.  Raw OData feed Note that by default, Internet Explorer applies an RSS Feed View to this data. This view hides much of the content, so if you want to see just the raw XML, you can switch off the “Turn on feed reading view” option in Internet Explorer. You can find this option by clicking Tools ➤ Internet Options ➤ Content ➤ Feeds and Web Sites (Settings).

■■Tip If you try this technique on a table with a sizable number of rows, the amount of XML data that LightSwitch returns can be large enough to crash Internet Explorer. If this happens, you can request fewer records by specifying a query expression in the URL.

Querying OData With OData, you can query data by appending query operators to the end of your URL. To return the first engineer, you would use this URL: http://localhost:41155/ApplicationData.svc/Engineers(1) You can use the OData protocol to access related records by using similar syntax. To return all issues that are assigned to the first engineer, you’d use the following URL: http://localhost:41155/ApplicationData.svc/Engineers(1)/Issues. If you want to find all engineers with a surname of Smith, you’d use http://localhost:41155/ApplicationData.svc/Engineers?$filter=Surname eq 'Smith'

471

Chapter 15 ■ Sharing Data with OData

■■Note  LightSwitch OData queries are case sensitive. In this example, the URL includes the word Engineers, rather than engineers. For a full list of OData query operators, visit the official OData website (http://www.odata.org/documentation/uri-conventions).

Securing OData Feeds The ability for a user to see all your data exposed through an OData endpoint can make you feel vulnerable. For instance, any user could easily view all of your engineer records by typing this address into their browser: http://localhost:41155/ApplicationData.svc/Engineers If this worries you, there sadly isn’t a way to switch off this behavior. However, you can secure your data by using the security features that LightSwitch provides. The first thing that you should do is to enable authentication. This prevents someone from accessing the endpoint without a password, or without being Windows authenticated. Next, you can limit access to your data by writing code in your entity’s CanRead, CanUpdate, CanDelete, and CanInsert methods. If you want to apply row-level access control, you can write code in your entity’s Entity_Filter method. To find out more about how to secure your data, refer to Chapters 21 and 22.

■■Caution  LightSwitch doesn’t provide access control at a column level. For example, let’s imagine that the Engineer table contains a salary column. If you want all users to be able to view engineer names but only managers to be allowed to view the salary details, you must split the salary data into a separate table. If not, your salary data will be visible via the OData endpoint.

Consuming LightSwitch Data Now that you understand how LightSwitch exposes your data using OData, I’ll show you how to access your data from outside of LightSwitch. In this section, I’ll show you how to connect to your data from both Microsoft Excel and .NET.

Connecting to LightSwitch Data from Excel With Excel 2013 and above, you can connect to LightSwitch data through OData. The benefit of Excel is that it allows users to analyze their data by using custom formulas, charts, or PivotTables. To create a connection, open Excel and select the OData option in the Get External Data group within the ribbon bar’s Data tab (Figure 15-9).

472

Chapter 15 ■ Sharing Data with OData

Figure 15-9.  Connecting to LightSwitch data using OData

Connecting to LightSwitch Data from .NET Any application that you build with .NET 3.5 or above can access LightSwitch data through WCF (Windows Communication Foundation) Data Services. The primary purpose of this section is to show you how to connect to LightSwitch data from an external .NET application. To do this, I’ll show you how to build an ASP.NET Web Forms application to allow users to create and view issue records. An ASP.NET Web Forms application is the easiest way to demonstrate the coding technique, but in practice you can apply the same technique on all types of .NET applications (for example, MVC, WPF, or Windows Forms applications). To create this application, start Visual Studio, create a new ASP.NET Web Forms application, and name it HelpDeskPortal. Right-click your project and select the “Add Service Reference” option from Solution Explorer. This opens the dialog that’s shown in Figure 15-10.

473

Chapter 15 ■ Sharing Data with OData

Figure 15-10.  Adding a service reference Enter the URL of your OData endpoint into the “Address” text box (e.g., http://WebServer/ YourAppName/ApplicationData.svc) and click the Go button to populate the Services list box. Click the OK button to complete the addition of the service reference. The service reference (also known as proxy or service client) enables you to access your LightSwitch entities in .NET code.

Adding Data from ASP.NET To demonstrate how to create records outside of LightSwitch, let’s see how to build a web page that users can use to create new issue records. To create this page, add a new Web Form to your ASP.NET project and name it CreateIssue.aspx. Next, add the code that’s shown in Listing 15-1. This code contains the markup for a page that includes data-entry controls and a button that performs the save operation.

474

Chapter 15 ■ Sharing Data with OData

Listing 15-1.  Webform for adding a new issue

The IssueSubject and IssueDescription text boxes provide controls to enable the user to enter a subject and description. The Add Issue button  calls the code that creates a new issue record in your LightSwitch database (Listing 15-2). Listing 15-2.  Webform code that adds a new issue

475

Chapter 15 ■ Sharing Data with OData

476

Chapter 15 ■ Sharing Data with OData

The first part of the code  creates the service context that enables you to access your LightSwitch data. The constructor requires you to supply a URL for your OData endpoint. This example hard codes the URL, but in practice it’s a good idea to store the value in your application’s web.config file. This would allow you to change the endpoint address after you deploy your application. If you’ve sensibly secured your application by enabling authentication (see Chapter 21), the commented-out line of code shows how you would supply a username and password. The next part of the code creates a new instance of an issue entity  and sets the value of properties  that include the subject, create date, target end date, and description. Visual Studio provides you with full IntelliSense suggestions in the code editor. This makes it easy for you to set your entity’s property values, because there’s no need for you to remember the exact names. LightSwitch provides an AddTo method for each entity in your data source. To add a new record, you would call the AddTo method that corresponds with your entity and then supply the entity object that you want to add. In this case, the method is called AddToIssues . Finally, you need to call the SaveChanges method to commit your changes to the database. If the data that your user enters fails validation, the SaveChanges method raises an exception, and you can handle this as you wish in the exception handler . With some extra styling, Figure 15-11 shows how this web page could look. Hopefully, this example shows how simple it is to work with LightSwitch data through the intuitive API.

Figure 15-11.  Web page that adds issues

477

Chapter 15 ■ Sharing Data with OData

Reading Data from ASP.NET You can very easily read and query LightSwitch data from .NET code. To demonstrate this, let’s create a page that displays the issues that are assigned to an engineer. To do so, add a new Web Form to your ASP.NET project and name it ViewIssues.aspx. From the toolbox, drag a grid view control onto your web form. Your markup should look the code that’s shown in Listing 15-3. Listing 15-3.  Web form that displays records

Now add the .NET code to the load method of your page, as shown in Listing 15-4.

478

Chapter 15 ■ Sharing Data with OData

Listing 15-4.  Web form code that populates a grid view control

Just like in the previous example, the first part of this code  creates the service reference context. The next line of code selects the issues that are assigned to the user timl . In practice, you would replace the hard-coded timl value with logic that determines the currently logged in user. But the important point of this code is that you can query your data by using the same LINQ query syntax that I showed you in Chapter 10. So, if you want to return just a single issue, you can write code that calls the FirstOrDefault method.

479

Chapter 15 ■ Sharing Data with OData

The final piece of code sets the data source of your grid view control  and data binds the issues data to the grid. Figure 15-12 shows what your final screen might look like with some extra formatting.

Figure 15-12.  Web page that shows issues

Connecting to LightSwitch from Other Platforms So far, I’ve showed you how to consume LightSwitch data from a .NET/ASP.NET application. Fortunately, it’s not difficult to connect to LightSwitch data from other platforms or devices. The most important step is to find a compatible OData client. Table 15-1 shows a list of common platforms and corresponding links to suitable OData clients for those platforms. When you connect to LightSwitch data from a different platform or language, the principles I showed you remain the same. For example, you would still call the same OData methods to access entities and to save your changes. Table 15-1.  OData Platforms and Clients

Platform

OData Client / Website

JavaScript

Datajs - http://datajs.codeplex.com/

Android / Java

OData4j - http://code.google.com/p/odata4j/

Windows Phone 8

OData client for Windows Phone 8 - https://msdn.microsoft.com/en-us/ library/windows/apps/gg521146(v=vs.105).aspx

iOS (Apple)

OData client for Objective-C http://odataobjc.codeplex.com/

PHP

OData SDK for PHP - http://odataphp.codeplex.com/

Ruby

ruby_odata - http://github.com/visoft/ruby_odata

480

Chapter 15 ■ Sharing Data with OData

Summary LightSwitch supports OData—a data-access protocol you can use to connect to external data sources and to share your LightSwitch data with other applications. Within your organization, you can use OData to connect to data in recent versions of SharePoint, Microsoft Dynamics CRM, and SQL Server Reporting Services. Externally, there are many other third-party data sources that you can use. In this chapter, I showed you how to connect to a travel-advice service. However, you can find many other data sources you can connect to through the official OData website and the Windows Azure Marketplace. To connect to an OData data source, you would use the Add Data Source wizard, just as you would for any other external data source. The connection process requires you to enter an endpoint. This is the web address that identifies the OData data source that you want to use. Depending on your data source, you might also need to supply a username and password. LightSwitch automatically creates service endpoints for each data source in your application. These endpoint addresses are made up of the root URL for your application, followed by the data-source name with a .SVC extension and the name of your entity set. For example, http://WebSite/HelpDesk/ ApplicationData.svc/Engineers is the address that returns all engineer records. Because users can access your raw data through a web browser, it’s a good idea to apply access control to your application. Chapters 21 and 22 will show you how to do this. You can use OData to attach to LightSwitch data from other applications. I showed you how to connect to LightSwitch from within Microsoft Excel and ASP.NET. In Excel, you can connect to OData data sources by using the import feature in the data section of the ribbon bar. In .NET, you can connect to LightSwitch data by adding a WCF Service Reference to an OData endpoint. This provides you with strongly typed access to entities and enables you to query, add, and update records using syntax that is simple and intuitive.

481

Part VI

Getting Data Out

Chapter 16

Creating Reports Having the ability to output data from applications can be crucial. Users often need to extract data in order to print or share with other users. Many users also search for ways to summarize or aggregate data so as to make better business decisions. Although LightSwitch includes no built-in report functionality, you can build reports with other products. You can then integrate those reports into your LightSwitch application. In this chapter, I’ll show you how to do the following: •

create reports with ASP.NET and SQL Server Reporting Services



create printable output that includes parent and child data



link and display reports from inside LightSwitch screens

The content in this chapter can be very beneficial for desktop applications. This is because unlike browser applications, there is no way to print from a desktop application.

Introduction to Reporting In this chapter, I’ll focus on Microsoft SQL Server Reporting Services and Microsoft ASP.NET. These products are great for creating reports. This is because both are free of charge, are well supported by Microsoft, and integrate well with LightSwitch. Both products share one thing in common: they can produce output you can access through a web address. Once you build the report content, you can display it inside a LightSwitch screen or add a link that opens the content in a new browser window. This web technique isn’t the only way to produce output from a LightSwitch application. Another method is to generate documents in Microsoft Word, Excel, or PDF formats. This is a big topic, and, therefore, I’ll cover this in the next chapter. Finally, you can purchase third-party reporting tools that integrate tightly into the LightSwitch development environment. One of the best known tools is the XtraReports suite from Developer Express.

Using ASP.NET to Create Reports To begin this chapter, I’ll show you how to create an ASP.NET Web Form that includes data from your LightSwitch application. Web Forms are simple to program, and I’ve chosen this technique for the reason of simplicity. You could also create a web page with ASP.NET MVC if that’s the technology that you prefer. In Chapter 15, I showed you how to create a simple page with ASP.NET. In this chapter, I’ll extend the example by showing you how to use the Application Server Context as a data source, how to display parent-child data with nested grids, how to use charts, and how to display data from navigation properties.

485

Chapter 16 ■ Creating Reports

To demonstrate this technique, I'll show you how to build a report that uses a grid view control to display the issue records that are assigned to an engineer. To illustrate how to use Web Form parameters, I’ll describe how to enable the user to show data for a specific engineer by supplying an ID value via the request URL. Figure 16-1 shows the appearance of the page that we'll create in this section.

Figure 16-1.  An ASP.NET Web Form that shows a grid of data On the topic of data connectivity, there are several ways to connect to LightSwitch data from an ASP.NET application. You can add an OData data source or you can use ADO.NET to connect directly to your Intrinsic database. In this example, I'll use the Server Application Context to connect to our LightSwitch application. This technique is straightforward, adheres to the LightSwitch security model, and requires minimal work to access related data and navigation properties.

Showing Grid Data on a Web Form Let’s review how to build your Web Form. First, create a folder called Reports in your Server project through Solution Explorer. Next, right-click the Reports folder and choose the menu item to add a new Web Form. Name your new file IssuesByEngineer.aspx. In the Web Form designer, add a label to display the engineer name, and a grid view control to display the issues that are associated with the engineer. Name your label EngineerNameLabel and the grid view control IssuesGrid. You can add these controls by setting the designer into either Design or Split mode and dragging the controls from the toolbox onto the screen designer. Alternatively, you can add these controls by typing the markup directly into the Source section of the screen designer. To further tidy the appearance of this page, you can define the columns that you want to show and use the Auto Format feature to apply header and alternate-row coloration. Figure 16-2 illustrates the layout of the page in split mode. The top part of this screenshot shows the ASPX markup, while the lower section shows the graphical view. The graphical view highlights the Auto Format and Edit Columns links.

486

Chapter 16 ■ Creating Reports

Figure 16-2.  Page layout in split mode If you choose not to define grid view columns, the grid will auto-generate a column for each column in your data source. When you define grid view columns through the Edit Columns link, you need to specify the data field that the column shows. This is done by specifying the DataField setting against the column. The DataField value corresponds to the property name that you want to bind to. A useful technique is to show related parent data in the grid by specifying a DataField value that references a navigation property. For example, in a grid that binds to a collection of issue records, you can display the name of the “closed-by engineer” in the grid by using the DataField value ClosedEngineer.Fullname. Note that you can easily format data columns with standard .NET format strings. This example formats the date columns in short-date formatting by setting the DataFormatString attribute value to {0:d}. To bind your grid view control to LightSwitch data, right-click your page, select the “View Code” menu item, and add the .NET code that’s shown in Listing 16-1.

487

Chapter 16 ■ Creating Reports

Listing 16-1.  Binding a grid view control to LightSwitch data

488

Chapter 16 ■ Creating Reports

This listing shows the code that runs when the page loads. This page requires the caller to supply an engineer ID value. The code uses the request parameters collection to retrieve the engineer ID value that the user supplies . The next block of code uses the application server context to connect to your LightSwitch data. The code retrieves the required engineer record and binds the grid view control to the issues navigation property of the engineer . You can apply standard query operators to customize the data that the grid view control binds to. For example, the commented-out section shows the syntax you would use to display the first 50 issue records in date-descending order . To include the IssuesByEngineer.aspx page in your build output, use the properties sheet to set the Build Action of your file to Content, and the Copy to Output Directory setting to Always. This is a step you need to carry out for any additional ASPX page you add to your project.

489

Chapter 16 ■ Creating Reports

At this point, you can view your web page. Run your LightSwitch project. When your application starts, use the IIS Express tray icon in the notification area of Windows to find the HTTP endpoint for your server project. Figure 16-3 illustrates an example project where the endpoint address is http:// localhost:1157/. To show data for a specific engineer, open a web browser and use the endpoint URL to build a fully qualified address that refers to your IssuesByEngineer.aspx web page. For example, you would enter the URL http://localhost:1157/Reports/IssuesByEngineer.aspx?EngineerID=1 to open the Issue report for the engineer with an ID of 1 (Figure 16-3). When the page loads, the final report will resemble the screenshot from Figure 16-1.

Figure 16-3.  Use the system tray icon to find the URL endpoint for your server project

Displaying Grids within Grids The structure of a typical business application includes related data, and it’s likely that you’ll want to show this type of data in a report. In this section, I’ll show you how to modify the page from the previous section to include child data. Figure 16-4 shows the end result of this example. To display the related issue-response records for each issue record, the technique requires you to nest a child grid view control inside a parent grid view control.

Figure 16-4.  A nested view of the data The key to nesting grid view controls is to add a child grid view control to a template field inside the parent grid view control. You would then write code in the RowDataBound event of the parent grid view control to set the data source of the child grid view control. Listing 16-2 shows the modification that you need to make to your parent GridView control.

490

Chapter 16 ■ Creating Reports

Listing 16-2.  Showing a set of nested grid view controls

As you can see from this listing, the parent grid view control defines a template field . Inside this template field, the markup defines a child grid view control called childGrid . The next step is to write the code that handles the RowDataBound event of the parent grid view control. Listing 16-3 shows the code that you need to add. Listing 16-3.  Binding a nested child grid view control

491

Chapter 16 ■ Creating Reports

This listing shows the code that runs when a specific row in the parent grid view control binds to the data source. This code uses the FindControl method to obtain a reference to the child grid view control . On the next line, e.Row.DataItem returns the issue object that the row binds to. The code sets the data source of the child grid view control to the issue responses navigation property of the issue record . You can now run your application, and the grid view control will show the nested data as shown in the screenshot at the start of this section (Figure 16-4). To extend this example further, you could nest additional grid view controls beneath your child control. To add a third-level grid view control, you would add it to the template field in the second-level grid view control. In the RowDataBound method of the second-level grid view control, you would write code that adds an event handler to handle the RowDataBound event of the third-level grid view control. This event handler would data bind the third-level grid view control using the same methodology you used to bind the second-level grid view control.

Creating Charts ASP.NET provides a chart control you can use to generate charts. With this control, you can produce all the usual chart types, such as pie, area, range, point, circular, and accumulation. To demonstrate this control, let’s look at how to create a page that uses a pie chart to summarize engineer issues by priority value. To build this example, create a new Web Form called PriorityChart.aspx in the Reports folder of your Server project (create the Reports folder if it doesn’t exist already). In the screen designer, drag a chart control from the Data section of the toolbox onto your Web Form. Change the chart type to Pie and set the X Value Member and Y Value Member settings to PriorityDesc and PriorityCount, respectively. You can either use the properties sheet or can modify the ASPX source code directly, as shown in Figure 16-5.

Figure 16-5.  Creating a chart: screen designer view in split mode Figure 16-5 shows the screen designer in split mode. The top part of this screenshot shows the ASPX markup while the lower section of the screen shows the graphical layout. The graphical section illustrates the area in the properties sheet where you can set the X and Y value members of the chart series. To bind your pie chart to data, add the code that’s shown in Listing 16-4.

492

Chapter 16 ■ Creating Reports

Listing 16-4.  Binding a chart control to LightSwitch data

493

Chapter 16 ■ Creating Reports

The code at the start of this listing follows the same pattern as the previous example did. When the page loads, the code uses the server application context to retrieve that engineer record that the caller provides via the request URL . This code uses a LINQ query to group the data into a structure that can bind to the chart control . This query uses the Issues navigation property of the Engineer entity as the data source. The query groups the related issue records by priority and produces a data structure that includes the priority description and a count of the issue records that match that priority. You can now run your page; Figure 16-6 shows how the pie chart appears at runtime. As before, you would run your page by building a web address that supplies the engineer ID in the request URL (for example: http://localhost:1157/Reports/PriorityChart.aspx?EngineerID=1) .

494

Chapter 16 ■ Creating Reports

Figure 16-6.  ASP.NET page showing a pie chart There’s a good reason why this example uses a navigation property as the data source. When you call the code that retrieves an engineer record, LightSwitch eagerly loads the related records. This makes it possible to group your issue data with a LINQ query, because the issue records are available to ASP.NET locally. If you attempt to query the data directly by using workspace.ApplicationData.Issues as the data source, your query would fail. The reason is because workspace.ApplicationData.Issues is of type IQueryable, and, therefore, LightSwitch would attempt to execute the query at the database. LightSwitch doesn't support this operation, because the data service cannot return non-LightSwitch entities to the ASP. NET client. Therefore, ASP.NET must load the data locally before you can query the data with LINQ. A simple way to do this is to use a navigation property. Another way is to use the take and execute methods to return EntityCollections you can work with. For example, you can use this syntax to return a set of Issue records that you can further query with LINQ: workspace.ApplicationData.Issues.Take(100).Execute(). Therefore, a caveat of this grouping technique is that it can be slow. Because the ASP.NET client needs to retrieve all of the required data from the database in order to carry out the grouping, this process can be slow if your underlying dataset is large.

Securing and Deploying Reports When you use the application server context as a data source, the standard LightSwitch security model protects your data. Provided that you configure authentication and authorization (I will explain how to do this in Chapters 21 and 22), you don't need to write any bespoke code to enforce access-control rules. Because the report files belong inside a folder within the Server project, the normal deployment process includes your custom ASP.NET pages in the output. Therefore, you don't need to carry out any additional tasks to include your reports in the deployment output that LightSwitch produces.

Using Microsoft Reporting Services Microsoft SQL Server Reporting Services provides a reporting platform that’s more powerful than simple ASP.NET pages. The additional features in Reporting Services include subscription notifications and the ability to export data in formats such as Microsoft Word and Adobe PDF. A full Reporting Services installation requires you to install and host the product on a server. If you don’t want the effort of setting up and maintaining a report server, you could use closely related Reporting Services technology to build “client” reports hosted through an ASP.NET page. In this section, I’ll describe both these techniques. I’ll begin by explaining how to install and create reports for a server installation of Reporting Services.

495

Chapter 16 ■ Creating Reports

Installing Reporting Services SQL Server Reporting Services is a part of the SQL Server product. You can obtain Reporting Services free of charge by installing the SQL Server Express with Advanced Services edition. If you already have SQL Server Express on your computer, you can upgrade a basic instance to the Advanced Services version by installing the setup package from the official Microsoft SQL Server website (http://www.microsoft.com/en-gb/ download/details.aspx?id=42299). SQL Server Setup installs a utility called Reporting Services Configuration Manager (Figure 16-7). You can use this utility to configure settings that relate to an instance of Reporting Services. In particular, you can use it to find out the Report Manager URL for your installation. Report Manager is a web-based application that you can use to upload and manage reports.

Figure 16-7.  You can use this tool to find your Report Manager URL Note that for some installations, you might encounter a permissions error when you open the Report Manager in Internet Explorer. The UAC (User Account Access) feature in Windows can cause this problem. If you encounter this problem, a possible fix is to run IE in elevated mode by right-clicking the IE icon and choosing the “Run as Administrator” option.

Installing the Report Designer Components To author reports for a server-based installation of Reporting Services, you need to install the software that enables you to do so. At the time of writing, the report-designer tools are included in a package called “SSDT October 2015 Preview in Visual Studio” (SSDT stands for SQL Server Data Tools). You can download this from the following website: https://msdn.microsoft.com/en-us/library/mt204009.aspx. Preview versions have not been thoroughly tested and can contain bugs. You might choose not to risk installing preview software on your development machine, and so, therefore, I’ll describe the alternative supported route. The RTM (released to manufacturing)version of SSDT 2015 does not include the Reporting Services components. If you want to author reports for a server-based installation of Reporting Services with the RTM software, you need to install a product called SQL Server Data Tools Business Intelligence. The Microsoft documentation abbreviates this to SSDT-BI. Assuming that you install SQL Server 2014 Express and Visual Studio 2015 on your computer, you need to download and install SSDT-BI for Visual Studio 2013

496

Chapter 16 ■ Creating Reports

from the same web page: https://msdn.microsoft.com/en-us/library/mt204009.aspx. At the time of writing, SSDT-BI for Visual Studio 2015 doesn’t exist, which is why you need to install the 2013 version. When you install SSDT-BI for Visual Studio 2013 on a computer that contains only Visual Studio 2015, the setup program installs the Visual Studio 2013 shell and exposes the report-designer tools and templates through the 2013 shell. Figure 16-8 shows this option in the SSDT-BI installer dialog. If you install SSDT-BI for Visual Studio 2013 on a computer with Visual Studio 2013 already installed, the installer adds the reporting components to your existing installation of Visual Studio 2013.

Figure 16-8.  Installing SSDT-BI If you chose not to install the SSDT preview software and want to build client reports that can run without the use of a report server, you must enable the SQL Server Data Tools feature in Visual Studio Setup (Figure 16-9). The default setup of Visual Studio doesn’t install this feature, so you might need to add it by running Visual Studio Setup. To modify an existing installation of Visual Studio, start Visual Studio setup through the Programs and Features section in Windows Control Panel.

Figure 16-9.  Make sure to check SSDT in Visual Studio 2015 setup The names of these products can confuse developers. To clarify the purpose of these RTM products, SSDT-BI is the tool that developers use to create SQL Server Reporting, Integration Services, or Analysis Services projects. SSDT is the Visual Studio add-in that provides client-side reporting templates, as well as support for database refactoring, schema comparisons, and templates to create database objects such as views and stored procedures. Although SSDT-BI and SSDT are different products, SSDT-BI used to be called

497

Chapter 16 ■ Creating Reports

SSDT in SQL Server 2012. Prior to SQL Server 2008, the SSDT-BI product was called Business Intelligence Development Studio, or BIDS for short. If you refer to the Internet for help on Reporting Services, it’s useful to understand the naming history of these products to avoid any confusion. To muddle matters even more, Microsoft has included the SSDT-BI components in the SSDT October 2015 Preview.

Creating Reports To show you how to build reports with Reporting Services, let’s create a report that summarizes issues records by department. The first step is to create a Reporting Services project. A Reporting Services project serves as a container for reports. With Reporting Services, you define reports in an XML-based format called Reporting Definition Language (RDL). To add a new project, open Visual Studio 2015, or open Visual Studio 2013 if you chose to install the 2013 components. In the case of the latter, if you installed SSDT-BI for Visual Studio 2013 on a machine without Visual Studio 2013, the installer adds a shortcut called “SQL Server Data Tools for Visual Studio 2013” in the Start Menu section of your computer. When Visual Studio opens, you can use the File menu to add a new Report Server project. Next, right-click the Reports folder of your project in Solution Explorer and choose the “Add New Item” option. From here, you can either choose the option to add a blank report or choose a Report Wizard item. For simplicity, I’ll show you how to create a report by using the wizard. The first stage of the wizard prompts you to select a data source. In an ideal world, you would configure Reporting Services to use an OData data source to connect to your LightSwitch application. Unfortunately, Reporting Services doesn’t support OData data sources. Therefore, the next best way to connect to your Intrinsic database is to configure a SQL Server data source. To configure a data source, you can either specify a connection to a deployed version of your SQL Server database or specify a connection to your localdb development database. To connect to your Intrinsic database, type (localdb)\MSSQLLocalDB into the Server Name textbox and use the “Select or enter a database name” drop-down to select the ApplicationDatabase.mdf database file for your project (Figure 16-10).

Figure 16-10.  Making a connection to your development database

498

Chapter 16 ■ Creating Reports

The next page of the wizard prompts you to enter a SQL query. Here, you can use the Query Builder button to construct a query. In this example, you can use the SQL that’s shown in Listing 16-5. This SQL returns a list of issues by engineer, with a corresponding count of issues broken down by priority. Listing 16-5.  SQL to return a list of issues priority counts, grouped by engineer

This SQL returns a typical aggregated view of data that managers often like to see in reports. Rather than give an example that returns a simple tabular view of data, I chose to include this example because it more closely illustrates the type of requirement that you would encounter in real life. This type of SQL can be convoluted, because it's often difficult to produce this type of flattened view of data from a relational structure. This listing demonstrates the code that T-SQL developers usually write to generate this type of view. It consists of a series of nested aggregations and select statements. This code is difficult to read, but for large datasets, you can achieve quicker performance by running SQL at the database rather than using matrix or cross-tab reports in Reporting Services. To clarify how this query works, Figure 16-11 shows the example output from each subquery. Starting with the Issues table, the first query uses a case statement to transpose the results. This produces a table structure with the columns engineer ID, low priority, medium priority, and high priority. Each row in this table stores the value 1 in the priority column that matches the issue record. The next select statement produces a sum of this result set, grouped by engineer ID. The final select statement joins the result with the Engineer table in order to include the firstname and surname values in the output.

499

Chapter 16 ■ Creating Reports

Figure 16-11.  How the aggregated SQL for report works The next step in the wizard prompts you to select a report type. The report types you can choose from are tabular and matrix. Select the tabular report option and complete the remaining steps in the wizard. You can provide a name for your report on the last page of the wizard. For this example, name your report IssuesByDepartment.rdl. When the report opens in the designer, you can use the Preview tab to see a runtime view of your report.

Working with the Report Designer Let’s take a closer look at the features in the report designer (Figure 16-12). The left part of the designer contains a Report Data pane. If you can’t see this item, you can reveal it by choosing the View ➤ Report Data option from the top-level menu. The Report Data pane is useful, as it enables you to manage the data items in your report. Specifically, you can use this pane to add images, parameters, or built-in fields (for example, page numbers) onto your report.

500

Chapter 16 ■ Creating Reports

Figure 16-12.  The Reporting Services designer The designer also provides a Toolbox pane. You can use this to add additional components onto your report, such as textboxes, lines, and subreports. Notice how the toolbox includes chart, gauge, and map controls. You can use these controls to build reports that are attractive and visually engaging. The top section of the designer provides two tabs you can use to switch between Design and Preview modes.

Managing and Adding Datasets In most cases, the items in a report bind to properties in a dataset. A dataset is an object that represents a tabular view of data. If you want to construct a report with multiple sections that bind to different tables, you need to add additional datasets to your report. You can do this by right-clicking the Datasets folder in the Report Data pane and selecting the “Add Dataset” menu item. To avoid any confusion, an important distinction is that a dataset object in Reporting Services is not the same as the dataset object in ADO.NET code. Importantly, a Reporting Services dataset does not have the same programmatic properties and methods as an ADO.NET dataset object. To illustrate another use for datasets, you can build reports where a user can filter the data that the report shows. To do this, you would define a parameter and modify your dataset query to refer to the parameter. Reporting Services can limit the parameter values that a user can select by showing the list of available options in a drop-down box. To accomplish this, you would configure the “Available values for this parameter” setting to refer to a dataset.

Displaying Data on a Report From the toolbox, there are three group controls you can use to display data in the body of your report. These controls are the table, matrix, and list controls. Let’s look at a brief overview of these controls. The table control displays data in rows and columns. In contrast, the list control is not as rigid. A list control enables you to display free-form data by binding data items to textboxes. Figure 16-13 illustrates the difference between the list and table layouts.

501

Chapter 16 ■ Creating Reports

Figure 16-13.  Table and list controls The matrix control groups the output by rows and columns. You would use this control to produce aggregated figures and to generate cross-tab or pivot-table type reports. Although the toolbox shows three separate controls, the table, matrix, and list controls are all the same control. When you add one of these controls to a report, the designer creates a control called a tablex. This is a highly flexible control that you can configure to render data in all three of these formats. For example, you can transform a table control into a list control by adding a rectangle control and adding textboxes to the rectangle. Alternatively, you can transform a table control to a matrix control by configuring the grouping of the data and binding textboxes to aggregated figures.

Writing Code A powerful feature in Reporting Services is the ability to customize reports with code. You can use this feature to apply custom logic and custom styles and formatting to reports. There are two ways to add custom code to a report: you can either use code from a .NET assembly or embed code into individual reports. Here are the characteristics of these two options: •

Use code from a .NET assembly: This option is ideal if you want to use your logic in multiple reports. You can take advantage of the classes in the .NET Framework, such as the string formatting and math functions.



Embed custom code: You can create custom methods in each report by rightclicking your report in the design view and selecting the “Report Properties ➤ Code” menu item. The benefit of embedded code is that it’s quick and easy to use. There’s no need to spend time compiling your .NET code assembly in a separate project before you use it in your report.

With embedded code, you can do something very powerful. You can set the value of a report property to an expression. This enables you (for example) to apply alternate row colors to a table by simply writing one line of code (Figure 16-14): =IIf(RowNumber(Nothing) Mod 2 = 0, "Silver", "Transparent")

502

Chapter 16 ■ Creating Reports

Figure 16-14.  Setting property values by using expressions This expression uses the IIf (conditional If) function. This function accepts three arguments: a test, the return value if the test succeeds, and the return value if the test fails. Figure 16-14 illustrates how to apply this expression to the BackgroundColor property of a table row. Although this technique is very powerful, it’s also easy to forget that it’s there. For example, when you click your mouse into the BackgroundColor property, the control shows a drop-down box that contains a list of colors. The presence of this drop-down can hide the fact that you can type free-text expressions into this control. Most of the other properties in the property sheet also include custom renderers, so this behavior applies not just to the BackgroundColor property.

Creating Drill-Through Reports Drill-through reports enable users to view additional details or related data by clicking a link. In the example I showed you, you could modify the report so that when a user clicks a department name, the report opens a list of issues for the selected department. The key to building a drill-through report is to set the Action property of your textbox control. The properties sheet contains a button next to the Action property. When you click this button, the designer opens a dialog that you can use to select when happens when the user clicks the textbox. You can open a subreport, go to a different URL, or jump to a predefined bookmark in your report.

Deploying Reports Reporting Services uses a web-based report server that allows end users to access reports through a web interface. As a developer, there are two ways to deploy your reports onto a report server. You can deploy them directly from the designer or you can upload RDL files through a web-based Report Manager.

Deploying a Report from the Designer The easiest way to deploy a report is to use the deploy feature that’s built into the designer. Before you can deploy your report, you need to configure some deployment settings. To do this, right-click your project in Solution Explorer and view the property window for your project, as shown in Figure 16-15.

503

Chapter 16 ■ Creating Reports

Figure 16-15.  The properties of a Reporting Services project Within this property window, the settings that you need to configure are: •

TargetReportFolder: Enter the folder on the Report Server where you want to publish your reports.



TargetDataSourceFolder: This specifies where the deployment function saves your data source files. If you leave this option blank, Visual Studio will publish your data sources into the TargetReportFolder.



TargetServerURL: To publish reports, you must enter a path to the virtual directory of your report server. As an example, this would be http://server/reportserver or https://server/reportserver (as opposed to the URL of the Report Manager).

Once you enter these details, you can deploy your reports by using the right-click “Deploy” option in Solution Explorer.

Importing a Report from Report Manager Another way to deploy a report is to upload your RDL file through Report Manager, as shown in Figure 16-16. This option is ideal if you can’t deploy your reports from within the designer. This can happen if your development computer isn’t connected to the same domain or network as your target report server.

504

Chapter 16 ■ Creating Reports

Figure 16-16.  The Report Manager interface To use this method, open a web browser and navigate to the Report Manager URL (for example, http://server/reportmanager). Navigate to the folder where you want to deploy your report or create a new folder. Click the Import link and upload your RDL file. Once you upload your report, you will need to configure the data source using the “data” option in Report Manager. After that, you’ll be able to view your report in your browser.

Using the Report Viewer Control With ASP.NET, you can host reports on a Web Form by using the report viewer control. This control can display reports from a Report Server, or, alternatively, you can configure the control to process reports locally without the need for a report server. To use the report viewer control in local processing mode, you need to supply a report file in RDLC (Report Definition Language Client-side) format. An RDLC file is a cut-down version of an RDL file. You can add RDLC files to your project through the “File ➤ New” dialog, or you can convert an existing RDL file into RDLC format. To demonstrate how to use the report viewer control, let’s look at how to convert the RDL file we created earlier into RDLC format and how to host it through an ASP.NET page. It's very easy to convert an RDL file to RDLC format. Simply rename your .RDL file with an .RDLC extension and import the file by selecting the “Add Existing Item” option from your project menu. The import process will convert your RDL file into RDLC format. Here are the steps to add a Web Form to host your report: 1. In the Server project of your LightSwitch application, right-click your Reports folder (create this folder if it doesn't exist already) and add a new Web Form called ReportPage.aspx. Use the properties sheet to set the Build Action to Content, and the Copy to Output Directory setting to Always. 2. Drag a SqlDataSource from the toolbox onto your Web Form. Configure your SqlDataSource to connect to your Intrinsic database. As in the Reporting Services example, you can point to your development database by entering the server name (localdb)\MSSQLLocalDB as your data source. 3. Next, enter the SQL Query for your data source.

505

Chapter 16 ■ Creating Reports

4. Drag a report viewer control from the Reporting section of your toolbox onto your Web Form. Also drag a script manager control onto your Web Form. This is necessary, because the report viewer control requires a script manager to work. 5. Use the smart tags panel in the report viewer control to select your RDLC file, and then use the link beneath to set the data source to your SqlDataSource (Figure 16-17) .

Figure 16-17.  Adding the report viewer control onto a web page This completes the design of your web page; you can now run your application. To view your report through your web page, you’ll need to copy your RDLC report to your application’s output folder. At debug time, this would be the location: HelpDesk\bin\Debug\Reports. Once you do this, you can open a web browser and view your report. To conclude this section, here are some final comments on building RDLC reports. Unlike Reporting Services RDL reports, you can bind RDLC reports to custom .NET objects. This means in theory, you can bind reports to LightSwitch objects and avoid writing SQL that can potentially be quite complex, depending on the output that you want to produce. In practice, however, there are some problems that you need to resolve when you bind to LightSwitch objects. For example, if you use the server application context to bind entities with navigation properties to a report, the entity code that LightSwitch auto-generates raises threading exceptions during the data-binding process (Figure 16-18). Alternatively, if you attempt to build a report that uses a LightSwitch OData data source, there’s no simple way to configure the report designer to add a list of available properties to the toolbox. Therefore, the simplest way to build an RDLC report is still to use a SQL Server data source.

Figure 16-18.  The code fails when the report viewer control binds to LightSwitch objects

506

Chapter 16 ■ Creating Reports

You should also be aware that when you author RDLC reports in Visual Studio, the Add Dataset dialog omits the option to populate a dataset with a stored procedure or custom SQL. If you want to populate a report with the output from custom SQL, you can build an RDL report in SSDT-BI and convert the report to RDLC format afterwards.

Linking Reports from Desktop Applications Once you have created a web-based report in ASP.NET or Reporting Services, you’ll need some way to link it to your LightSwitch application. There are two approaches you can use, which are: •

To open your web report in a new browser window



To display a web report inside a LightSwitch screen

Opening Reports in a New Browser Window To open your web page in a new browser window, you can either shell an instance of your browser (in a desktop application) or use Silverlight’s HtmlPage class (in a browser application). To demonstrate this technique, I’ll show you how to build a screen that contains a list of engineers. Each engineer row will include a link that opens the IssuesByEngineer report in a new browser window. To create this example, carry out the following steps. 1. Add a reference to System.Windows.Browser assembly in your Client project. 2. Create an Editable Grid screen that’s based on the Engineer table and name your screen EngineersManagerGrid. 3. In the command bar for the data grid, add a new button called OpenEngineerIssueReport. Use the drop-down to change the control type to "link." Figure 16-19 shows the appearance of your screen.

Figure 16-19.  Design view of a screen to open reports

507

Chapter 16 ■ Creating Reports

Now, add the code that’s shown in Listing 16-6 Listing 16-6.  Opening web pages in a new browser window

508

Chapter 16 ■ Creating Reports

Listing 16-6 shows the code that runs when a user clicks a link to open the report. The first part of this code builds the URL to the IssuesByEngineer.aspx web page. The code appends the ID of the record that the user selects in the data grid to the URL . This example hard codes the root part of the URL. In practice, it’s wise to store this in a table or somewhere you can modify after you deploy your application. The next part of the code detects your application type . For a desktop application, the code uses COM automation to shell an instance of your browser . For a browser application, the code uses the Silverlight HtmlPage class instead . When you now run your application, you’ll be able to view engineer timesheet reports by clicking the button that appears against each engineer record (Figure 16-20) .

Figure 16-20.  Clicking a button in the grid opens the report in a new window

Displaying Reports inside LightSwitch Screens Rather than open web pages in a new browser window, you can show reports inside your LightSwitch screen by using the Silverlight web browser control. However, a slight disadvantage is that browser applications don’t support this control, so this method works only for desktop applications.

Showing Reports in a Screen To demonstrate how to use the web browser control to display a web page on a screen, let’s look at how to add the web page with the RDLC report to the EngineersManagerGrid screen that you created above. 1. Open the EngineersManagerGrid screen. Click the Add Data Item button and add a new string property called ReportProperty. Make sure to uncheck the “Is Required” checkbox. 2. Drag ReportProperty onto your screen and change the control type from a textbox to a custom control. You can add this control onto a new tab layout to keep it separate from the existing items on your screen. 3. In the properties sheet for ReportProperty, click the Change link and set the control type to System.Windows.Controls.WebBrowser control. 4. In the properties sheet for ReportProperty, set the Min Width and Min Height fields to 300. Your web page won’t appear if you leave the width and height properties set to Auto. Figure 16-21 shows the design-time view of your screen.

509

Chapter 16 ■ Creating Reports

Figure 16-21.  Design-time view of your screen Now, append the code that’s shown in Listing 16-7 to the Created method of your screen. This completes your screen; Figure 16-22 shows how it looks at runtime. Listing 16-7.  Displaying a web page with the web browser control

510

Chapter 16 ■ Creating Reports

Figure 16-22.  Report shown inside a LightSwitch screen

■■Caution  LightSwitch renders the contents of a web browser control in a windowing plane that is separate to the Silverlight content. Therefore, the screen content can appear out of place when a user resizes or scrolls your screens. The web browser content also appears on top of all other controls on your screen. It won’t honor any z-order values that you might try to apply. If you place an auto-complete box control above the web browser control, for example, the drop-down contents will appear behind the web browser control. There isn’t any easy way to fix this behavior. You should therefore thoroughly test any screens that use the web browser control.

Showing Reports in a List Screen Another way you can use the web browser control is to apply it to a screen that contains a data list or data grid. As the user changes the selected record via the list or grid control, the page that appears in the web browser control refreshes itself to match the currently selected record. To demonstrate this technique, I’ll show you how to modify the EngineersManagerGrid screen. I’ll describe how to add a list of engineers, and how to add a web browser control that displays the IssuesByEngineer report that corresponds to the selected engineer. Follow these steps to carry out this example: 1. Build the web browser custom control from Chapter 13 (Listing 13-9) into an assembly called ApressControls.dll. 2. Open the Engineers Manager Grid screen. In a new tab, drag the Engineers collection onto your screen and set the control type to a list control. 3. Drag the Engineer ID property of the selected item onto the screen and change the control type from a label to a custom control. Make a note of the name that designer assigns to this property. In this example, the designer sets the ID of this control to Engineers_SelectedItem_Id. 4. In the properties sheet, click the Change button and open the Add Custom Control dialog. Use the Browse button to select the ApressControls.dll file, and set the custom control type to ApressControls.WebBrowserControl. Set the Min Width and Min Height fields to 300. 5. Add the code to the Created method of your screen, as shown in Listing 16-8. 6. This code uses a value converter called IdToReportUrlConverter. Create this class immediately after your EngineersManagerGrid class. Listing 16-8 shows the code that you’ll need to add.

511

Chapter 16 ■ Creating Reports

Figure 16-23 shows the screen designer. This completes the screen-design tasks; you can now run your application. Figure 16-24 shows the runtime view of the screen.

Figure 16-23.  Report shown inside a LightSwitch screen

Figure 16-24.  Report shown inside a screen based on the List and Details screen template

512

Chapter 16 ■ Creating Reports

Listing 16-8.  Showing a web page on a LightSwitch List and Details screen

513

Chapter 16 ■ Creating Reports

This code uses the web browser custom control from Chapter 13. This custom control exposes a dependency property called URIProperty. Whenever this property changes, the control navigates to the value of the URIProperty. In this example, we added an ID property onto the screen and changed the control type to the custom web browser control. Therefore, the underlying data context of this control is the numeric ID value. The code calls the FindControl method to return a reference to the custom control . Make sure that the name you pass to this method matches the name of your custom control (Engineers_SelectedItem_Id, in this example). On the next line, the SetBinding method  binds the numeric ID to the custom web

514

Chapter 16 ■ Creating Reports

control’s URIProperty. The URIProperty needs to be in the format of a web address. Therefore, the IdToReportUrlConverter value converter  takes the numeric ID and returns a web address that opens the report for the selected engineer .

Printing Reports An important requirement in many business applications is having the ability to print documents. Unfortunately, desktop applications include no support for printing. But with a small modification to your ASP.NET reports, you can call JavaScript code that opens the browser’s Print dialog. This would allow the user to send the contents of the web page to the printer. Follow these steps to modify the IssuesByEngineer report so that it includes a Print button: 1. Open the IssuesByEngineer.aspx page in the designer. 2. Switch your page to the source view. Just above the grid view control, add the following line of code:

This line of HTML defines a Print button. When the user clicks this button, it triggers a piece of JavaScript that opens the browser’s Print dialog. Figure 16-25 shows how this button looks at runtime.

Figure 16-25.  Printing a report

■■Tip  If you use the web browser control from the System.Windows.Controls namespace, a useful method that you can call from your C# or VB code is the WebBrowser.InvokeScript method. This allows you to call JavaScript functions that are defined on the web page that the control shows. For example, if you didn’t want to include a Print button on an actual web page, you could call the JavaScript Window.Print method by calling the InvokeScript method.

515

Chapter 16 ■ Creating Reports

Linking Reports from HTML Client Applications With HTML client applications, you can very easily show external web content on LightSwitch screens. This technique relies on custom controls. I showed you how to use custom controls in previous chapters. Therefore, this section provides a brief explanation of how to show the ASP.NET and Reporting Services output on a LightSwitch screen.

Displaying Content inside an iframe An effective way to show web content on a screen is to use an iframe. Here’s how to use an iframe to display the pie chart page from earlier in this chapter. First, create a Browse screen and name it ReportOverview. For this example, you can leave the data source of the screen blank. In the section where you want to show your content, create a rows layout and change the control type to a custom control (Figure 16-26).

Figure 16-26.  Design view of the overview screen: change the rows layout to a custom control Now, add the render code for your custom control, as shown in Listing 16-9. Listing 16-9.  Custom control code to show report in an iframe

The code in this listing defines an HTML iframe. The first line of code determines the root URL of your application and uses this to build a path to your report . You can now run your screen; Figure 16-27 illustrates the appearance at runtime.

516

Chapter 16 ■ Creating Reports

Figure 16-27.  An HTML client screen that includes a pie chart

Adding Hyperlinks Rather than show the web content in an iframe, you can easily modify your custom control so that it shows a hyperlink instead. To make this change, modify the render code for your custom control as shown in Listing 16-10. Listing 16-10.  Adding hyperlinks

This code replaces the iframe with an HTML hyperlink. The target='_blank' attribute configures the hyperlink to open the content in a new browser window . You can now run your screen; Figure 16-28 shows how it looks at runtime.

517

Chapter 16 ■ Creating Reports

Figure 16-28.  Runtime view of a screen with a hyperlink

Summary LightSwitch comes with no built-in reporting function. To help extract data from a LightSwitch application, this chapter showed you how to build reports with ASP.NET and SQL Server Reporting Services. Both of these products generate content that you can access through a web address. In the second part of this chapter, I showed you how to link and display this content inside LightSwitch screens. In the first part of this chapter, I showed you how to build reports with ASP.NET. Within a Web Form, you can use the grid view control to display tabular data and the chart control to display charts. An effective way to display parent-child data is to use a set of nested grid view controls. To apply this technique, you would add a child grid view control to a template column inside the parent grid view control. You would then write code in the RowDataBound event of the parent grid view control to bind the child control. To bind the web controls to data, I showed you how to use the LightSwitch server application context. This enables you to bind to strongly typed LightSwitch data objects. This technique honors any security-access rules you define in LightSwitch, and another benefit is that you easily access related data through navigation properties. The ASP.NET chart control enables you to display data through all the usual chart types. This includes line, bar, area, and pie. I showed you how to aggregate data with LINQ and how to display the results with a pie chart. The LightSwitch data sources you can use to aggregate data with LINQ include navigation properties and local entity collections that you return by calling the execute method on an entity set. After the ASP.NET examples, I showed you how to use SQL Reporting Services. With Reporting Services, you can generate neat output that renders well when printed. The full version of Reporting Services includes powerful features such as scheduled reporting and email notifications. You can obtain a free, cut-down version of Reporting Services by installing SQL Server Express with Advanced Services. To author reports in Visual Studio 2015, you need to install the SSDT October 2015 Preview for Visual Studio 2015. If you don’t want to install preview software on your computer, you can install a tool called SQL Server Data Tools–Business Intelligence (SSDT-BI) instead. At the time of writing, a 2015 version of SSDT-BI doesn’t exist. Therefore, the latest RTM version of SSDT-BI will integrate the report designer components into Visual Studio 2013. If you don’t have Visual Studio 2013 on your computer, the installer will install the report designer components into a standalone version of Visual Studio 2013. Reporting Services defines reports in an XML format called RDL (Reporting Definition Language). The toolbox in the Reporting Services designer includes three controls you can use to display data. These are the table, list, and matrix controls. The table control displays data in rows and columns; the list control enables you to author free-form layouts; and the matrix control displays aggregated data in a cross-tab or pivot-`table manner. With Reporting Services, you can customize your reports with embedded code, or with .NET code from a separate assembly. I showed you how to use this feature to style and format your reports. An additional feature is the ability to build drill-through reports. With this feature, users can click links in a report to open secondary reports.

518

Chapter 16 ■ Creating Reports

Reporting Services is a server-based solution. Microsoft provides similar client-side report capabilities through RDLC reports. You can render RDLC reports without the need of a server. I showed you how to display an RDLC report on ASP.NET page through the use of the report viewer control. To author RDLC reports, you need to install the SSDT feature from Visual Studio setup. Another way to create RDLC reports is to convert existing Reporting Services RDL files to RDLC format. To display an ASP.NET or Reporting Services page on a desktop application screen, you can use Silverlight’s web browser control, or you can write code that opens the page in a web browser. Desktop applications that run in the browser don’t support the web browser control. For these types of applications, you can open your report in a new browser window by using Silverlight’s HtmlPage object. For HTML client applications, you can add a custom control that displays your report in an iframe, or you can add a custom control that adds a hyperlink to your report.

519

Chapter 17

Generating Office Documents A common requirement for developers is the ability to produce office documents from applications, such as invoices, receipts, or reports. By adding Office document support, you can also satisfy the needs of users who like to extract data to Excel for analysis purposes. In this chapter, I’ll describe Office-integration techniques, which include how to do the following: •

generate Word documents with the OpenXML SDK



automate Microsoft Excel and carry out mail merges with Microsoft Word



generate PDF files on desktop applications

The de facto tool that businesses use is Microsoft Office. Therefore, this chapter focuses on Microsoft Office formats and discusses ways that you can generate Office documents in both desktop and HTML client applications.

Overview of Techniques In this chapter, I’ll describe two techniques you can use to produce Office documents. The first method uses the OpenXML SDK to create documents on the server, while the second produces documents on the client by accessing Microsoft Office through COM automation. The technique you choose depends on your application type, as shown in Table 17-1. Table 17-1.  Reporting Techniques That You Can Use, by Application Type

Technique

Desktop Application

Web Application

Use the OpenXML SDK to generate documents on the server





Use Microsoft Office and COM automation to generate documents on the client



The server-based OpenXML technique works for all application types. In contrast, the client-based automation technique works only for desktop applications in desktop client mode. COM automation is not compatible with browser-based desktop applications because of Silverlight security restrictions. The COM client automation technique requires the user to install Microsoft Office, so there’s slightly more set-up work in order to use this technique.

521

Chapter 17 ■ Generating Office Documents

Using the OpenXML SDK A popular and well-known method for creating office documents is the OpenXML SDK. You can use this SDK to create Word, Excel, and PowerPoint files. This technique is possible because Microsoft Office uses an XML-based document format. This SDK therefore produces documents in the newer Microsoft Word DOCX, Excel XLSX, and PowerPoint PPTX formats. Technically, this solution consists of two main parts. The first part involves writing the server-side code to handle the request from the user to generate a document. The same server-side code uses the SDK to build the actual Office file. The second part is the client-side code that enables the user to open or save the document locally. Figure 17-1 illustrates the process, which I’ll describe in more detail as this chapter progresses.

Figure 17-1.  Overview of the OpenXML document-generation technique In the remainder of this section, I’ll demonstrate this technique by showing you how to build a Word document that contains a summary of timesheet entries.

Installing the OpenXML SDK To use the OpenXML SDK, download and install the SDK from the Microsoft website. To do this, download the Open XML SDK 2.5 for Office package from the following page: http://www.microsoft.com/en-gb/download/details.aspx?id=30425 The download package includes two files: the OpenXML SDK installer and an OpenXML SDK tool (Figure 17-2). Make sure to include the OpenXML SDK tool (OpenXMLSDKToolV25.msi). This tool provides code-generation and document-validation features that will help you more easily work with the SDK.

522

Chapter 17 ■ Generating Office Documents

Figure 17-2.  Choose the option to download both the SDK and the tool

Implementing the Command Pattern Before we write the document-generation code, there are some preparatory tasks we need to carry out. The first is to build the framework that allows users to initiate the server-side document-generation process. When Microsoft first released LightSwitch, there was no simple way for developers to call server code from LightSwitch screens. To overcome this problem, a popular workaround was to use a technique called the command (or operation table) pattern. This technique still plays a useful role in LightSwitch development today. The technique relies on a table that exists for the sole purpose of executing commands. You attach code to the inserting or inserted methods of this table, which enables you to call server-side code by adding rows to your table. If you want to pass arguments to your server-side methods, you must define table properties. For this example, Figure 17-3 shows the schema of the table that supports the command pattern.

Figure 17-3.  Screenshot of command table In this example, we’ll add code that creates the document to the row inserting method. The EngineerID property enables the user to specify the engineer record that appears in the report. When the server completes the document, it will store the file in the ReportData property within the same table. You can then use the same techniques that I showed you in Chapter 11 to enable users to download and view the file.

523

Chapter 17 ■ Generating Office Documents

Using the SDK to Build a Document Let’s now look at how to build a document with the Open XML SDK. There are two broad strategies you can adopt. The first approach is to prepare a template document with Microsoft Word. Once you create a template file, you can write code that copies the template document and apply your customizations to the copy. The second approach is to build your document entirely in code. Since the template approach requires far less code, this is the approach that most developers recommend, and this is the technique that I’ll describe in this section. The first step is to build your template document with Microsoft Word. Figure 17-4 shows the document that I’ll use in this example.

Figure 17-4.  Use Word to build your document This document includes a header section with engineer details and a table in the body of the document that shows the timesheet entries for the engineer. The technique we’ll use to populate the header section of the document relies on bookmark substitution. To add the timesheet entries into the body of the document, we’ll call OpenXML SDK methods to insert rows.

Adding Bookmarks to a Word Document Bookmarks enable you to locate sections within a Word document. To insert a bookmark, click the “Insert” menu and click the “Bookmark” item. This opens a dialog you can use to enter a name and insert a bookmark.

524

Chapter 17 ■ Generating Office Documents

Figure 17-5.  Inserting a bookmark in a Word document For the purpose of this example, add two bookmarks to your document. Name your bookmarks EngineerFirstname and EngineerSurname. By default, Word doesn’t show bookmarks, which can make it difficult to author documents. However, you can make bookmarks visible by checking the “Show Bookmarks” checkbox in the Word Options dialog box (shown in Figure 17-6). In Word 2010 or above, you can open the Word Options dialog through the File item in the ribbon bar. When you enable the “Show Bookmarks” option, Word uses a gray I symbol to indicate the locations of the bookmarks within your document.

Figure 17-6.  Enabling the option to show bookmarks in Word

525

Chapter 17 ■ Generating Office Documents

Titling Tables in a Word Document To add the timesheet records to the document, we’ll use the OpenXML SDK to add rows to the existing table. This technique requires us to be able to locate tables in code. A method we can use to locate tables in a Word document is to identify the tables with a title. To add a title to a table, right-click the table and choose the “Table Properties” menu item. In the Table Properties dialog, switch to the Alt Text tab and use the Title textbox to enter a title (Figure 17-7). To recreate the example in this section, add the title TimesheetEntries to your table.

Figure 17-7.  Adding a title to a Microsoft Word table

526

Chapter 17 ■ Generating Office Documents

If Word grays out the Alt Text textbox, make sure that you switch off compatibility mode for the document. You can do this through the settings that appear beneath the File menu in Word. By titling objects in Word, you can use both LINQ and the OpenXML SDK to locate the object in code. Experts in Microsoft Word often use tables to lay out, position, and align the contents in a document. To achieve a finely tuned layout, users often hide borders, merge table cells, and nest tables. Because tables play such an important role in the layout of a document, adding titles and captions to objects can help simplify the development task.

Building a Document with the SDK Once you prepare your Word template file, you can write the code that uses the SDK to build a Word document. A prerequisite is to make your Word template available in the Server project of your LightSwitch solution. To do this, create a folder called Reports in your Server project. Right-click your Reports folder and click the “Add Existing Item” menu item. Add your Word template file and name it TimesheetTemplate.docx. Once you do this, open the properties sheet for the file and set the Build Action to Content and the Copy to Output Directory setting to Copy always. Once you add your Word template file, follow the steps to build the document-generation code. To use the SDK, you need to add references to the following DLLs to your Server project: •

DocumentFormat.OpenXml.dll



Windows.Base

Assuming that you install the SDK in the default location, you’ll find the OpenXML DLL in the following location (in a 64-bit installation of Windows): C:\Program Files (x86)\Open XML SDK\V2.5\lib\DocumentFormat.OpenXml.dll The next step is to open the TimesheetReport table in the designer. Click the Write Code button, select the Inserting method, and add the code that’s shown in Listing 17-1. Make sure to add a reference to the DocumentFormat.OpenXml.Packaging namespace at the top of your code file with either the Imports or Using statement.

527

Chapter 17 ■ Generating Office Documents

Listing 17-1.  Code to generate a Word document with the OpenXML SDK

528

Chapter 17 ■ Generating Office Documents

529

Chapter 17 ■ Generating Office Documents

530

Chapter 17 ■ Generating Office Documents

531

Chapter 17 ■ Generating Office Documents

532

Chapter 17 ■ Generating Office Documents

To create a report for a specific engineer, a user would add a new record to the TimesheetReport table and set the EngineerId value of the new record to the ID of the engineer who should appear in the report. The first part of this code retrieves the engineer record from the Engineer table . The next part uses LINQ to retrieve the timesheet records for the current month . Following these data-retrieval tasks, the code builds a path to the template Word document  and loads the contents into a byte array . To return the full physical path of the Word template document, the code calls the MapPath method. When you call this method, you can use the ~ symbol to reference the root of the website that hosts your Server project. Once the code opens the Word document, it calls a method called InsertBookMark value to substitute the engineer data values into the body of the report . The next section of code locates the timesheet table in the document . To locate the table, the code uses LINQ to find the first table property object with the caption TimesheetEntries. The parent of this table property object is the timesheet table. The next block of code loops over the timesheet collection. For each timesheet record, the code clones the first empty row in the table  and uses a method named GetParagraph to set the cell values. Note that, in this example, the very first row contains the table column headings. The final section of this code saves the changes to the document and saves the output into the TimesheetReport table .

Calling the Document-Creation Procedure from the Client The whole solution requires you to create a screen that users can use to add records to the TimesheetReport table, and to therefore create Word documents. To demonstrate the client design tasks, let’s look at how to build a screen that shows a list of engineers. Against each engineer record, we’ll add a link that builds the document and generates a Save dialog that enables the user to save the document locally on their computer. Figure 17-8 illustrates the final appearance of this screen in an HTML client application.

Figure 17-8.  An HTML client screen that users can use to generate timesheet documents

533

Chapter 17 ■ Generating Office Documents

Opening Documents from an HTML Client Application To create this screen in an HTML client application, add a Browse screen for the Engineer table. Change the control type for the Engineers collection to a table. Inside the table row, add a command called DownloadTimesheet. Figure 17-9 shows the layout of your screen.

Figure 17-9.  Layout of the HTML client screen Now, add the JavaScript code that’s shown in Listing 17-2. Listing 17-2.  JavaScript code that creates the document

534

Chapter 17 ■ Generating Office Documents

At this point, you can build your application and run the screen. When you click the Download Timesheet button, the server-side code will create the Word file, and once this process completes, the browser will prompt you to save the output file locally. The first part of this code adds a new record in the TimesheetReport table . The code adds the record in a new data workspace to help keep the data operation independent from the rest of the application. The code sets the engineer ID of the new TimesheetReport record and calls the SaveChanges method  to commit the changes to the server. This call initiates the server-side code that creates the Word document. When the save operation succeeds, the TimesheetReport record will contain the Word document. The code in this listing calls an IE-specific method called msSaveOrOpenBlob . This method opens the IE Save dialog to enable the user to save the Word document locally. The TimesheetReport entity contains a base-64 encoded representation of the file. The purpose of the base64toBlob method is to convert this data into a binary representation that works with the Save dialog. The base64toBlob method utilizes a built-in JavaScript method called atob  to provide the underlying conversion. For this example, I included the msSaveOrOpenBlob technique for brevity. A caveat of this technique is that it works only in HTML5-compatible versions of IE. If you require a cross-browser solution, you can use the technique I showed you in Chapter 11, or you can replace the call to msSaveOrOpenBlob with a more compatible method. One way to do this is to use the FileSaver library, which you can download from https://github.com/eligrey/FileSaver.js/.

Opening Documents from a Desktop Application For desktop client applications, the screen-design steps follow closely the HTML client design technique. To create the client screen, add an Editable Grid screen for the Engineer table and add a button inside the data grid called DownloadTimesheet. Figure 17-10 shows the layout of this screen.

535

Chapter 17 ■ Generating Office Documents

Figure 17-10.  Layout of the desktop client screen Now, add the .NET code that’s shown in Listing 17-3. Listing 17-3.  .NET code that creates the document

536

Chapter 17 ■ Generating Office Documents

537

Chapter 17 ■ Generating Office Documents

Just like in the HTML client example, this code uses a new data workspace to add a new record to the TimesheetReport table . The code sets the engineer ID of the new TimesheetReport and calls the SaveChanges method  to commit the changes to the server. As before, this call initiates the server-side code that creates the Word document. Once the document-generation process succeeds, the code opens the Silverlight Save dialog and prompts the user to save the Word file locally. As usual with this type of operation, the code uses the UI thread to open the Silverlight Save dialog . A caveat of this code is that it works only for applications in desktop client mode, and not for desktop browser applications. A workaround for this issue is to use a Silverlight custom button control, as I described in Chapter 13. This concludes the section on generating documents on the server. With this technique, the files will accumulate in the TimesheetReport table. Depending on your circumstances, it might be wise to write code that clears this table, or you might want to move the data onto a different table or into a more permanent storage location.

■■Tip For desktop applications in desktop mode, you can open the file in the registered application rather than show the Save File dialog. You will find out how to do this later in this chapter.

Building Documents with Code A difficulty with the OpenXML SDK is that you can struggle to work out exactly how to perform a task in code. For example, suppose that you want to add odd and even headers, indexes, or Word art objects to your document. With limited knowledge of the OpenXML SDK, it can be very difficult to work out exactly how to perform these tasks. A trick that can help you is to use the Open XML SDK 2.5 Productivity Tool. This tool provides a feature that generates the C# code for a document. By default, the installer installs the Open XML SDK 2.5 Productivity Tool into the folder C:\Program Files (x86)\Open XML SDK\V2.5\tool. To start the tool, run the OpenXmlSdkTool.exe file from the installation folder. Once the tool opens, click the Open File button to open a document that contains the content you want to deconstruct. Next, click the Reflect Code button. When you do this, the tool generates and displays the C# code in the center pane (Figure 17-11). You can then use this reflected code to help build your document.

538

Chapter 17 ■ Generating Office Documents

Figure 17-11.  Use the productivity tool to determine the C# code for a document

Performing COM Automation In this section, I’ll show you how build documents on the client with the use of COM automation. To begin, I’ll briefly describe some of the features of COM automation. A characteristic of client-side COM automation is that this technique works only for desktop applications in desktop mode. Given this restriction, you might wonder what the benefits of COM automation are. After all, you could just as easily write server-side code that works both for desktop and browser applications. The biggest benefit of COM automation is that it allows you to integrate more deeply with the client. For instance, you can access local resources such as files, web cameras, and printers. This type of integration isn’t possible with code that runs on the server. To demonstrate a task that’s difficult to accomplish with server-side code, I’ll show you how to carry out a Microsoft Word mail merge with LightSwitch. But to provide you with a simpler introduction to COM automation, I’ll begin this section by showing you how to automate Microsoft Excel.

Generating Excel Documents Out of the box, LightSwitch already includes some support for outputting data to Excel. Any data grids you add to the screen can include an Excel button that allows the user to output the data to Excel. Although this built-in feature works well, you can produce better output by building Excel documents with COM automation. For example, you can customize exactly where the data goes, apply different fonts and styles, and add additional worksheets. You can also create documents in the older Excel XLS format, which is something you can’t easily do with the OpenXML SDK.

539

Chapter 17 ■ Generating Office Documents

To demonstrate how to work with Excel, let’s build a spreadsheet that shows an issue record and the associated issue-response records on the same worksheet. As Figure 17-12 shows, the ability to export parent and child data into the same workbook is a feature that users can find helpful.

Figure 17-12.  Final spreadsheet To build this example, create a Details screen for the Issue table and include the IssueResponse data collection on your screen. In the screen designer, create a button called ExportToExcel, as shown in Figure 17-13.

Figure 17-13.  Layout of the screen Now, enter the code that’s shown in Listing 17-4. Make sure to use the imports or using statements to add a reference to the System.Runtime.InteropServices.Automation namespace.

540

Chapter 17 ■ Generating Office Documents

Listing 17-4.  Microsoft Excel automation code

541

Chapter 17 ■ Generating Office Documents

542

Chapter 17 ■ Generating Office Documents

At this point, you can run your screen. When you click the Export to Excel button, your application starts Excel and shows the exported data. Let’s look at how this code works. To avoid any errors, the first part checks that your application is a desktop application, rather than a browser application . You can add the same logic to the button’s CanExecute method to prevent the button from appearing in browser applications. The next part of the code creates a COM reference to Excel by calling the AutomationFactory class’s CreateObject method . The way that you instantiate a COM object is to supply a string argument called a ProgID. In this example, we supply the ProgID Application.Excel. But, if you want to automate Microsoft Word instead, for example, you’d replace this with a ProgID of Application.Word. The technique of creating a COM object by passing a ProgID string is called late binding. The advantage of late binding is that it doesn’t depend on any particular version of Excel. As long as a version of Excel exists on the client computer, your code will work. A major disadvantage, however, is that during design time, Visual Studio’s code designer doesn’t provide you with any IntelliSense. This means that you can easily write buggy and syntactically incorrect code that LightSwitch won’t catch until runtime. The next part of this code creates a new workbook by calling the Workbooks.Add method . The next line populates the top part of the spreadsheet with issue data. It then inserts the issue-response data into the rows beneath . At the end of the process, the code shows the Excel document to the user by setting the visibility property of the Excel application object to True .

Sending Documents Directly to a Printer Rather than showing the document to the user on the screen, you can send your Office document directly to a printer and quit the Office application without saving changes. This technique allows you to send reports to a printer without any additional user intervention. This is a feature that users often find useful. For example, you could use this technique to add a button that prints a receipt or invoice. To highlight the usefulness of COM automation, it’s worth noting that this is a feature that you can’t easily add to an HTML client application. The best that you can achieve in HTML client applications is to open the browser’s Print dialog.

543

Chapter 17 ■ Generating Office Documents

Listing 17-5 shows the code that you would use to send the Excel workbook from the previous example directly to a printer. In this code, the Close method accepts an argument that configures what happens when Excel closes. You can configure Excel to discard or save changes, or you can let the user decide. To make Excel close a document without saving changes, you would pass the value 0 to the Close method. Listing 17-5.  Printing and closing an Excel document VB: File: HelpDeskVB.DesktopClient\Screens\IssueDetail.lsml.vb   excelWorkbook.PrintOut excelWorkbook.Close(0) excelApp.Quit   C#: File: HelpDeskCS.DesktopClient\Screens\IssueDetail.lsml.cs   excelWorkbook.PrintOut(); excelWorkbook.Close(0); excelApp.Quit();

Performing Mail Merges with Word Continuing on the theme of COM automation, I’ll now describe how to carry out a mail merge by automating Microsoft Word. The purpose of this example is to demonstrate something slightly complex that you can accomplish with COM automation that would otherwise be difficult to achieve through server code. There are many practical reasons why you might want to perform a mail merge. These reasons aren’t limited to just building letters, in the conventional sense. For instance, you can use a mail merge to build a report with sections that include multiple header and child sections. You can also use this technique to build name badges, surveys, or other business forms. To demonstrate this technique, I’ll show you how to mail merge a letter with data from the department table.

Creating a Mail Merge Word Template The underlying document that makes mail merges possible is a mail merge template. To create a mail merge template, open Word and create a new document. From the ribbon bar, select the Mailings group, click the Start Mail Merge button, and select the “Letters” option. Click the Select Recipients button and choose the “Type New List” option. This opens the New Address List window, as shown in Figure 17-14.

544

Chapter 17 ■ Generating Office Documents

Figure 17-14.  Creating the mail merge fields The New Address List window displays the mail merge fields as columns in the grid. As this figure shows, the default mail merge fields include Title, FirstName, LastName, and several more. You can add fields by clicking the Customize Columns button. For the purpose of this demonstration, add the two new mail merge fields called DepartmentName and DepartmentManager. When you click the OK button to close the New Address List dialog, Word prompts you to save the list as a new Microsoft Office Address List file (or MDB file, if you’re using an earlier version of Word). Name your data file MailMergeData. Once this process completes, Word will enable the Insert Merge Field button in the ribbon bar. At this point, you’ll no longer need this data file. However, you need to create a data file in order to add the mail merge fields to your document. The next step is to write your letter and to insert the mail merge fields in the appropriate places (Figure 17-15). When you complete your document, save your template file as MailMergeTemplate.dotx.

Figure 17-15.  Click the Insert Merge Field button to add a mail merge field

545

Chapter 17 ■ Generating Office Documents

Writing the Mail Merge Code Once you add your Word template document, it’s time to write the code that carries out the mail merge. To demonstrate the technique, let’s build a screen that performs a mail merge with department data. First, create an Editable Grid screen that’s based on the Department table. Name your screen BuildLetter. Add a button called CreateMailMerge and add the code that’s shown in Listing 17-6. Listing 17-6.  Mail merge code

546

Chapter 17 ■ Generating Office Documents

547

Chapter 17 ■ Generating Office Documents

548

Chapter 17 ■ Generating Office Documents

549

Chapter 17 ■ Generating Office Documents

550

Chapter 17 ■ Generating Office Documents

Listing 17-6 includes plenty of code. Although this process may seem complex, the overall process distills into two main parts. 1. The code creates a data document in Microsoft Word format and populates it with data from your LightSwitch screen. 2. The code uses your template file to create a new Word document and sets the mail merge data source to the document you created above. The code then initiates the actual mail merge. Let’s now take a closer look at this code. The entry point to this process is the CreateMailMerge_Execute method. This is the method that runs when the user clicks the Create Mail Merge button. This process uses the MailMergeTemplate.dotx template file to create a new Word document . Next, the code calls a method called CreateMailMergeDataFile . This creates a data document called DataDoc.doc and sets the data source of the new Word document to be this data document. It does this by calling Word’s CreateDataSource method . This method requires you to supply the column headers for your data. The column names you define must match the names of the mail merge fields that you defined in the New Address List dialog. In this example, these headings are called DepartmentName, DepartmentManager, and Address1 . The remaining code in the CreateMailMergeDataFile method loops through the records in the Departments collection and calls the FillRow method to populate the data document (DataDoc.doc). Before you execute the mail merge, you can write additional code to fine tune the contents of your document. To demonstrate this technique, the code in this listing inserts a letter reference at the end of the document. To accomplish this, the code moves the insertion point to the end of the document and calls code to insert text. The code inserts the text “Our Ref” followed by the recipient name and date. To append the name, the code inserts a mail merge field that binds to the DepartmentManager mail merge data item . By doing this, the actual data substitution occurs during the mail merge process. You can use bookmarks that you define in your template document to help locate sections that you want to want to customize with code. This provides a powerful method that you can use to tailor the contents of a document at runtime. The code that moves the insertion point to the end of the document accomplishes this by calling a method called EndKey. The wdStory argument configures the method to move the selection to the end of the document (as opposed to the end of a column or line), and the wdMove argument configures the method to move the insertion point (as opposed to extending the selection from the current position to the new position). The remaining code in this procedure performs the mail merge by calling the Execute method on the wordMailMerge object . This completes the mail merge process, and the remaining code tidies up the objects that it declared earlier. You can optionally add code here to delete the DataDoc.doc file if you want.

551

Chapter 17 ■ Generating Office Documents

Just before the call to the Execute method, the code sets the Destination property  of the wordMailMerge object to wdSendToNewDocument. This represents the numeric value of 0, which configures Word to show the document to the user. Table 17-2 shows the other acceptable values you can set. So, for example, you could configure the process to send the output directly to a printer. Table 17-2.  Constants You Can Use to Set the Mail Merge Destination

Name of Constant

Value

Description

wdSendToNewDocument

0

Word shows the mail merge in the document.

wdSendToPrinter

1

Word sends the mail merge to a printer.

wdSendToEmail

2

Word sends the mail merge to your default email client.

wdSendToFax

3

Mail merge will be sent to a fax.

A standard practice that developers apply when they write automation code is to detect the mode of the application and to disable desktop-specific functions in browser applications. The code in the CreateMailMerge_CanExecute method contains logic that does this . You can now run your application; Figure 17-16 shows the mail merge screen at runtime.

Figure 17-16.  Word mail merge at runtime To conclude this section, let’s look at some behavior you should be aware of when you write code that recourses through a data collection. This code populates your data document by using your screen’s Departments collection. By default, screen collections show only 45 records at a time. Therefore, you might want to increase this by changing the value of the “No. Of Items To Display Per Page” textbox. If you want to mail merge all of the records in a table, you can modify your code so that it uses a query rather than a screen collection.

Distributing the Template with the LightSwitch Client In the mail merge example I just showed you, the code retrieves the Word template file from a UNC file share. The biggest disadvantages of this technique are that the code works only on the internal network, and that it won’t work in environments where Windows file sharing is disallowed.

552

Chapter 17 ■ Generating Office Documents

You can overcome this problem by embedding your Word template in your application’s XAP file. There are several other pros and cons of using this technique, which are summarized in Table 17-3. Table 17-3.  Template-Distribution Techniques

Distribution via a File Share

Distribution via the XAP File

This technique works only within your local network.

You can use this technique in applications that you deploy over the Internet.

You can easily update your file template after you deploy your application.

You’ll need to rebuild and redeploy your LightSwitch application if you want to make changes to your template file.

There isn’t any impact on the load time of your application.

Adding your Word template to the XAP file makes it larger, which in turn makes your application slower to load.

This technique is more fragile because there’s a dependency on a file outside of your application.

This technique is more robust, as everything is self-contained.

Let’s look at how to modify the code from Listing 17-9 to retrieve the Word template from the XAP file, rather than from a UNC file share. To add your MailMergeTemplate.dotx file to your XAP file, use Solution Explorer to add a new folder to your client project. Name this folder Resources. Next, right-click the Resources folder and use the “Add Existing Item” option to add your Word template file. Once you add your template file, open the properties sheet and set the Build Action property of the file to Content, as shown in Figure 17-17.

Figure 17-17.  Setting the Build Action to Content Listing 17-7 shows how to extract a file from your XAP package and then save it into the My Documents folder on the client computer. The code saves your template into the My Documents folder because security restrictions in Silverlight limit the places where you can save files on the local file system. You would add this code to Listing 17-6, just before the initial part that calls the CreateObject method to create a COM reference to Word.

553

Chapter 17 ■ Generating Office Documents

Listing 17-7.  Saving the Word template to the My Documents folder

The first part of this code calls the GetResourceStream method . The purpose of this method is to return resources that are embedded inside a XAP file. This method requires you to supply a relative path that identifies your resource. This path doesn’t require any leading slashes—if you add a leading slash, your code won’t work. Also notice how the directory separator uses a forward slash (/) rather than a backslash. This specifies a letter template that belongs in the Resources folder. But, if you add the template file to the root of your project, the Uri string that you would use would simply be "LetterTemplate.dotx". After the code obtains a resource stream, it builds a string that defines the location within the My Documents folder , where the code will later save the file. In practice, you might want to save the template to a more specific location, and check that no file with the same name exists before you create your file. Next, the code calls the WriteAllBytes method to write the contents of the resource to file . The extraction of the Word template file from the XAP file is now complete. To finish, you can modify the call to the wordApp.Documents.Open method in Listing 17-6 so that it opens the template from the My Documents folder, rather than from the UNC file location.

554

Chapter 17 ■ Generating Office Documents

Creating Adobe PDF Documents To conclude this chapter, I’ll show you how to generate PDF documents with a Silverlight library called silverPDF. The PDF format provides several benefits. This format preserves the layout and positioning of your document; it is compatible on a wide range of devices; and it’s generally more difficult for a user to alter the contents of a PDF document. There are many third-party PDF libraries you can use. In this section, I chose to use silverPDF because of its simplicity and popularity. silverPDF is based on two other open source projects: iTextSharp and PDFsharp. If you’ve used these libraries before, the code in this section will look familiar. To get started with silverPDF, download the silverPDF.dll file from the CodePlex website at http://silverpdf.codeplex.com/. Next, add a reference to the silverPDF.dll assembly from your client project. At this point, you can begin to build PDF documents with the library. To show you how to use the PDF library, let’s look at how to add a PDF Export button to a screen that’s based on an issue record. To create this example, create an Add Edit Issue screen for the Issue entity. Add a button called ExportToPDF and insert the code that’s shown in Listing 17-8. Listing 17-8.  Building PDF documents with the silverPDF library

555

Chapter 17 ■ Generating Office Documents

556

Chapter 17 ■ Generating Office Documents

At this point, you can run your application. Let’s look at how this code works. The start of this procedure creates a PDF document  and adds a page to the document . Next, the code defines a set of fonts that you can apply to the elements in your document . The next section defines an XGraphics object . This is an object you can use to add content to your PDF document. It exposes various Draw methods that you can call to create graphical elements, as shown in Figure 17-18. DrawString is a method you can call to add text to your document, and the code calls this method several times, starting with a call that creates a piece of header text . The DrawString method requires you to supply the font name, color, X-Y coordinates, sizing, and alignment details so as to properly display the text.

Figure 17-18. silverPDF draw methods

Notice how this code invokes the PDF-creation logic on the main UI dispatcher. If you don’t do this, LightSwitch throws an “Invalid cross-thread access” exception. This is because Silverlight guards many of the objects in the System.Windows namespace (and others) and permits the use of these of objects only on the main Silverlight dispatcher thread. Internally, the silverPDF library uses some of these protected objects. The final part of this procedure calls the PDFDocument object’s Save method to save the PDF file to the user’s My Documents folder. Silverlight’s security model allows you to only save documents to certain folders, one of which is the My Documents folder. Figure 17-19 shows how the final document looks at runtime.

557

Chapter 17 ■ Generating Office Documents

Figure 17-19.  PDF output produced with silverPDF

■■Tip  With Microsoft Word 2010 and above, you can natively save documents in PDF format. You can therefore create PDF files by using COM automation and the Word object model (in desktop applications). You would create your PDF file by calling the Save method on your Word document, and then passing in the file format type of 17 (this relates to Word’s wdFormatPDF enumeration value). The C# code would look like this: myWordDoc.Save(17);

Summary A common user requirement is the ability to generate Office documents from a LightSwitch application. This functionality enables users to generate documents such as invoices, receipts, or reports. It also enables users to output data to Excel for further analysis. In this chapter, I showed you two ways to generate documents. The first method uses the OpenXML SDK to create documents on the server. The second method produces documents on the client with COM automation. The server method works for desktop and HTML client applications, whereas the COM automation technique works only for desktop applications in desktop mode. Starting with the server-based method, I showed you how to apply a technique called the command pattern. This technique helps you overcome a problem with LightSwitch screen development. The problem is that it can be difficult to call specific server-side code from the client. The command pattern relies on a table that exists for the sole purpose of executing commands. You attach code to the inserting method of this table, which enables you to call server-side code by simply adding rows to your table. You can pass arguments to your server-side methods by defining table properties. The example I showed you uses the OpenXML SDK to generate a Word document when a user adds a row to a command table. The code saves

558

Chapter 17 ■ Generating Office Documents

the output document back into the command table. This makes it possible for you to retrieve the document by using the techniques that I showed you in Chapter 11. The OpenXML SDK provides an object model that you can use to generate documents. It can be difficult to build a document from scratch, because this can require a lot of code. You can simplify the process by basing your new document on a predefined template document. In the case of a Word document, you can predefine elements such as tables, headings, and footnotes in a template document. In the copy of your document, you can then write code that clones, modifies, or deletes these predefined elements. This is easier than creating these elements from scratch in code. I also described how to add bookmarks to a template document so as to insert LightSwitch data into a document, and how to write code with the OpenXML SDK that inserts data values into those bookmark locations. To demonstrate inserting line data into a document, I showed you how to clone rows from an existing Word table and how to populate the table cells with data. For desktop applications, you can use COM automation to interact with the applications that exist on the end-user PC. The benefit of this technique is that it allows you to integrate more deeply with the client and enables you to access local resources such as files, web cameras, and printers. To demonstrate this technique, I showed you how to export screen data to Microsoft Excel. The benefit of a custom export feature over the basic export function in the data grids is that you can output header and line data and apply custom styles and formatting. To give a more complex example of COM automation, this chapter described how to create a Word mail merge with LightSwitch data. You can use mail merges whenever you need to populate a Word document with data. This technique can be useful if you need to generate reports. The mail merge technique relies on code that extracts your LightSwitch data into a data document. Subsequent code then merges this data document with your Word template file. A useful task you can perform with Microsoft Office integration is to send documents directly to a printer. You can carry out this process without the user ever seeing the Office application on the desktop, and once the file prints, you can discard the document. This enables you to add a button that prints output onto a screen without requiring any further user intervention. In the final part of this chapter, I showed you how to generate PDF documents with a Silverlight library called silverPDF. Some users prefer the PDF format because it looks more consistent across different computers, and is more difficult for users to edit. To use the silverPDF library, simply download it and add a reference to the assembly in your client project. Once you do this, you can write code that builds your PDF document.

559

Chapter 18

Sending Email One way to usefully extend your application is to add email support. With email, you can deliver alerts and notifications. You can also build application features that users can use to send messages directly from a LightSwitch screen. In this chapter, I’ll show you how to do the following: •

send notifications from the server



create an email service to allow users to send messages from screens



use client code to automate Microsoft Outlook

To demonstrate how to add notification capabilities to your application, I’ll show you how to send a message when the status of an issue changes to “closed.” Next, I’ll show you how to build an email service with WCF (Windows Communication Foundation). I’ll then describe the corresponding code you can use to call the service from your screens. The technique I’ll show you is useful, because you can extend it to call other third-party web services. For example, you could modify the code I show you to add stock prices or currency conversion rates to your application.

Overview to Sending Email In this chapter, I’ll describe three techniques to send email from your applications. The first technique initiates a message when a change in data occurs. You can use this technique to send email notifications and alerts. For example, you could apply this technique to an order-processing system to send automated emails whenever the status of an order changes. In many other scenarios, you might want to add the ability to send messages through actions that are not associated with a change in data. To cater to these situations, I’ll show you to develop an email service that you can call from your desktop and HTML client screens. In the final part of this chapter, I’ll show you how to send emails with Microsoft Outlook integration. This method works well for users who spend a lot of time in Outlook. A benefit of this technique is that any messages you send in this way will appear in the user’s Sent Items folder. You can also carry out additional Outlook tasks when you create the message. This could include workflow items such as creating tasks, calendar items, or contacts.

561

Chapter 18 ■ Sending Email

Sending Email Notifications To begin, I’ll show you how to send email messages when a change in data occurs—we’ll send an email notification when the status of issue record changes to “closed.” Before I describe this technique, there are some preparatory tasks you need to carry out. To send emails, you need to have access to an SMTP Service. Within an organization, a system administrator can often provide you with access to such a service. Alternatively, you could use the SMTP service that your email provider or ISP (Internet Service Provider) provides. Failing that, you can install your own SMTP service. IIS includes an in-built SMTP service, which you can install through the Windows Features section of the Control Panel. There are a few remaining steps. First, I’ll describe a technique you can use to store SMTP credentials in your application. Next, I’ll show you how to build a reusable email library to maximize code reuse. Finally, I’ll describe the code that sends the actual message.

Using Configuration Settings to Save Credentials Your SMTP details can change over time, so it makes good sense to save the settings in a place that you can easily modify after you deploy your application. One option is to store these settings in a user-defined table. Another way is to store your settings in a configuration file. With this approach, you can set these values by editing your application’s Web.config file after you have deployed your application. You can find this file in the root of your published application. To create application settings, right-click your Server project and open the properties window for your project. Switch to the Settings tab and create a set of application-scoped settings to store your email credentials, as shown in Figure 18-1.

Figure 18-1.  Creating configuration settings in your server project The configuration file provides a safe place in which to store your credentials. ASP.NET provides a method you can use to encrypt any sensitive settings. For reference, you can use the aspnet_regiis utility with the pe switch on your deployment server to encrypt these settings. One thing to be aware of is that when you modify a web.config file on a live server, IIS will restart the application pool. When this happens, your application will respond more slowly when it receives the next request. Your application will also lose session-state information if you configure your IIS server to use the “in process” session option.

562

Chapter 18 ■ Sending Email

If you choose to store your configuration details in a table, the benefit is that users can change the configuration values without needing file-level access to the server.

Creating a Reusable Email Class Let’s review the steps to create an email helper class to support the code in this chapter. The benefit of a helper class is that it saves you from duplicating code if there are several places in your application from which you want to send messages. Also, you can more easily reuse code in other .NET applications when you extract the logic into a separate class. To add this class, create a new class in your server project. To help keep your project tidy, you can create this class in a folder called UserCode. Name your class SMTPMailHelper and add the code that’s shown in Listing 18-1. Listing 18-1.  SMTP mail helper class and method

563

Chapter 18 ■ Sending Email

564

Chapter 18 ■ Sending Email

565

Chapter 18 ■ Sending Email

The SmtpMailHelper class defines a static method called SendMail, which is the method you would call to send an email message. The code in this method creates a new instance of a MailMessage object . This object represents an email message, and you can use it to set properties such as the recipient address, subject, and message body. Table 18-1 shows a list of properties you can set. Table 18-1.  MailMessage Object Properties

Name

Description

Attachments

Gets the collection used for storing file attachments

Bcc

Gets a collection of blind carbon copy (BCC) recipients

CC

Gets a collection of carbon copy (CC) recipients

DeliveryNotificationOptions

Gets or sets the delivery notifications

From

Gets or sets the from address

IsBodyHtml

Gets or sets a value indicating whether the message body is in HTML

Priority

Gets or sets the message priority

ReplyToList

Gets or sets the list of reply to addresses

Sender

Gets or sets the sender's email address

566

Chapter 18 ■ Sending Email

The next section of code checks for the presence of an HTML tag in the message body . If this test succeeds, the code sets the format of the email message to HTML . This line of code allows you to author HTML emails by including an HTML tag at the start of your message body. The benefit of an HTML email is that you can apply custom styles, colors, and formatting to your message. The helper class includes file-attachment support, and the next section of code defines the logic that implements this functionality . The final part of the method sends the message by calling SmtpClient’s Send method . The SmtpClient class represents the object that sends a message. You must initialize this object with the SMTP server address and port number. You can optionally set authentication credentials if your server requires this. The commented section shows the code you would use to supply a username and password value. For the SMTP server setting, you can supply either a server name or an IP address. In addition to the Send method, the SmtpClient class also includes a method called SendAsync that you can call to send your message asynchronously. To initialize the SmtpClient object with SMTP settings, this code calls methods in .NET’s System. Configuration namespace to retrieve the settings that you added earlier in this chapter. Note that with VB, you can more easily access configuration settings through the My.Settings object. This completes the code for your email helper class. If you want to use this class in multiple LightSwitch projects, an effective way is to compile the code into a separate class library project. You can then use the code by referencing the library in your Server project.

■■Tip  If you have a Google Mail (or Gmail) account and want to use the SMTP service that Google provides, there are settings that you need to apply. The server name you need to use is smtp.gmail.com. The port number that Google uses is 465, rather than the standard SMTP port of 25. Next, set the DeliveryMethod attribute of SmtpClient object to SmtpDeliveryMethod.Network. To authenticate to the service, set the SmtpClientcredentials property with the credentials of your Google account.

Sending the Email Now that you’ve created your email helper class, let’s review how to write the code that sends the message from your server. To demonstrate this technique, I’ll show you how to send an email message when the status of an issue record changes to “closed.” To implement this feature, we’ll add code in the Issue entity’s Updating method. To create this example, open your Issue table in the table designer. Click the Write Code button and select the Updating method. Now, enter the code in Listing 18-2.

567

Chapter 18 ■ Sending Email

Listing 18-2.  Sending email when a user updates a record

568

Chapter 18 ■ Sending Email

You can now run your application and test this logic. To do this, open an existing issue record and change the status to “closed.” At this point, the server should send an email message just before the server saves the record to the database. The first part of the code checks whether the user has changed the issue status to “closed” . It does this by checking that the original status isn’t “closed,” and then tests if the new status value is “closed.” Next, the code calls the SendMail method in the helper class to send the message. Note that the SendMail method includes the capability to append a file attachment. If you want to include an attachment with your message, you can retrieve the data from a table. Alternatively, you could call the File.ReadAllBytes method from the System.IO namespace to attach a file from the file system of your server.

■■Tip  If your code fails to send the email, there are a few simple things that you can check. First, do you have any firewalls or antivirus applications that are blocking your SMTP traffic? Some antivirus programs protect against mass-mailing worms and block any outgoing SMTP traffic. Second, email servers such as Microsoft Exchange or the SMTP service that IIS provides may require you to specify the IP addresses of the devices that can access the service.

569

Chapter 18 ■ Sending Email

Initiating Emails from LightSwitch Clients The technique that I just showed you relies on changes to data. Most likely, there will be scenarios in which you want to send an email regardless of a change to data. In this section, I’ll show you how to build this functionality. I’ll show you how to build a WCF web service that sends SMTP mail messages. Once you build this service, you can call it from both your HTML client and desktop applications. The service that we’ll build includes two variations of the same method. The first method is a REST (Representational State Transfer)-based method that returns data in JSON (JavaScript Object Notation) format. This method supports HTML client applications, where you can easily call REST-based web services with AJAX. The second method uses SOAP (Simple Object Access Protocol) and returns data in XML format. The purpose of the SOAP method is to support desktop clients. Although you can connect to REST-based web services from Silverlight, you cannot create a service reference to a REST service. A service reference provides you with a client proxy that exposes typed objects that you can use to access your web service. It makes it easier for you to program your application, because the code editor provides IntelliSense suggestions for your web-service methods, and Visual Studio won’t compile your application if you fail to specify the correct arguments for a method. Although the primary purpose of this section is to demonstrate how to send email, a secondary objective is to show you how to call a web service from your application. With web services, you can incorporate many value-added features into your application. For example, you could connect to an SMS gateway to send text messages, or you could connect to web services that return stock prices, currency conversion rates, or postal-code lookups. You can carry out a web search on “Free WebService” in order to find web services you can use, or, alternatively, you can visit a site such as http://www.webservicex.net/ws/default.aspx.

Building an Email service Let’s now write the code to build our email service. The first step is to add a WCF web service to your LightSwitch application. To do this, right-click your Server project, click Add ➤ New Item, and select the “WCF Service” option, as shown in Figure 18-2. Name your service MailService.svc.

Figure 18-2.  Adding a new WCF web service

570

Chapter 18 ■ Sending Email

The WCF service template creates two files in your project. The first file contains the interface, and the second file includes the implementation. The interface defines the architecture of your web service. It defines the method names, parameters, and return types of your web methods. To build a SOAP-based method that you can access from a Silverlight client, you need to define an interface in order for the underlying connectivity to work. But for a purely REST-based web service, you don’t need to define an interface if you don’t want to. Listing 18-3 shows the content you need add to your interface file. In order to apply the correct code decorations, you need to add a reference to the System.ServiceModel.Web.dll assembly and add using or import statements that reference the System.ServiceModel.Web namespace at the top of your code file. Listing 18-3.  Defining the interface for your web service

571

Chapter 18 ■ Sending Email

The code in Listing 18-3 defines the two web service methods. You can configure each method by applying the WebInvoke attribute. The Method property defines the HTTP verb that the caller must supply in order to invoke the web method . The verbs that developers most often use are GET and POST. You should use the value GET for web methods that return data. For web methods that insert and update data, you should set this value to POST. When a client issues a HTTP POST request, servers and clients will not cache the result of the web method. Therefore, you should use the GET verb if your method always returns the result for a given set of input values. The technical term that describes this behavior is an idempotent operation. An important point here is that you must specify the method value in uppercase. If you enter the value post in lowercase, the server will return a 404 error when you try to call the web service. In normal circumstances, you often encounter 404 errors when the resource is missing on the server or when you enter an incorrect web address. If you encounter this error by using lowercase for the HTTP verb, you can waste hours investigating before working out the exact cause of the problem.

572

Chapter 18 ■ Sending Email

The ResponseFormat property specifies the data format of the message that the method returns . For a SOAP-based method, the return data is in XML, whereas for a REST-based method, the return type is JSON. For VB.NET, make sure that you specify the LightSwitchApplication namespace at the top of your code file. When the WCF service template creates your initial interface file, it doesn’t specify a namespace for your interface. If you don’t specify a namespace, you won’t be able to refer to the interface in the endpoint section of your web.config file. The inability to do this will prevent your service from working correctly. After you define your interface, the next step is to add the code that defines the implementation. To do this, add the code in Listing 18-4 to your MailService.svc.cs or MailService.svc.vb file. Listing 18-4.  The code that implements the Send Mail routine

573

Chapter 18 ■ Sending Email

574

Chapter 18 ■ Sending Email

This listing contains the code that implements your service. The SendMailREST and SendMailSOAP methods call the SendMail helper method that you created earlier in this chapter. These methods return a string result that indicates the result of the email procedure. With VB.NET, make sure to add the code that sets the namespace to LightSwitchApplication. In conjunction with this change, you also need change the service attribute value from .MailService to LightSwitchApplication.MailService in the first line of your MailService.svc file. To open your MailService.svc file, right-click the file in Solution Explorer and select the “View Markup” menu item. Do not try to open the MailService.svc file directly by double-clicking it in Solution Explorer. When you double-click an SVC file, Visual Studio opens the code behind file rather than opening the actual SVC file. The final step is to configure your service by modifying some of the settings beneath the system.serviceModel section of your web.config file, as shown in Listing 18-5.

575

Chapter 18 ■ Sending Email

Listing 18-5.  Changes to the web.config file

There are three main things you need to set up in this file: the service, the service behavior, and the endpoint behavior.

576

Chapter 18 ■ Sending Email

The first section declares your service. The code in this section defines two endpoints for your service: a default REST-based endpoint and a SOAP-based endpoint. The address attribute specifies the endpoint address that the caller can use to access the server. In this example, the code sets the address to soap . This configures the endpoint to listen on an address that is prefixed with the word soap. An example URL would be: http://webserver/soap/MailService.svc. The service-behavior configuration turns on metadata publishing by setting the httpGetEnabled attribute to true . When you set this value to true, it allows you to view the WSDL (Web Service Description Language) page for your web service. This page is important, because you can use it to check that your web service functions (at a basic level). For desktop client applications, you need to enable this setting so that you can add a service reference to your web service from Visual Studio. The next line configures the service to include the exception details in any error message that the service generates. This setting can assist you greatly when you debug your application. However, it’s good practice to disable this option when you deploy your application, for security reasons. The final section defines an endpoint behavior that includes the webHttp element . This is the endpoint behavior that you need to define in order to support a REST-based service. At this point, your WCF service is complete, and you can carry out some preliminary checks. To do so, build and run your project. Next, open a web browser and browse to your service’s WSDL page. The web address you would use is the root URL for your server followed the name of your service followed by the question mark character. In this example, the address is http://localhost:49814/MailService.svc?. If you now see the page that’s shown in Figure 18-3, you’ve successfully created your service. If not, you’ll probably see an error page with the exception details, which you can use to help fix your code. With WCF services, incorrect binding, endpoint, or security settings in your web.config file are the most likely causes of problems. To diagnose WCF errors, a good place to start is to use Windows Event viewer. IIS and IIS Express will log WCF errors in the Application event log.

Figure 18-3.  Opening your service in a web browser

577

Chapter 18 ■ Sending Email

Sending Messages from HTML Client Applications Now that you have a working email service, let’s review how to call the service from an HTML client application. I’ll show you how to add an Email button to an issue screen. This feature will allow the user to click the button and to forward the issue details, as shown in Figure 18-4.

Figure 18-4.  Screenshot of final screen To build this screen, create a View screen for the Issue entity. To enable the user to enter an email address, use the Add Data Item button to add an Email Address property to your screen. Uncheck the “Is Required” checkbox and name your property Recipient. Drag the Recipient property onto your screen and change the control type to be an email editor control. Next, add a button called Send Email. To tidy the appearance of your screen, you can move the email controls to a separate tab. Figure 18-5 illustrates the design-time view of the screen. Now, add the code that handles the execute event, as shown in Listing 18-6.

578

Chapter 18 ■ Sending Email

Figure 18-5.  Design time view of screen Listing 18-6.  Calling the SendEmail handler page via AJAX

579

Chapter 18 ■ Sending Email

The code in this method returns a promise object. It does this by wrapping the logic in a call to the msls.promiseOperation method . The promise object places the screen in a “busy” mode and prevents the user from interacting with the application while the call to the web service takes place. The next part of this code builds the URL to your web service endpoint . The SendMailREST method requires you to supply emailTo, subject, and body arguments. The next line of code builds a JavaScript object that represents the arguments that you’ll pass to the SendMailREST method . The next section of code calls the stringify method to convert this JavaScript object to a JSON string . The code then uses the jQuery ajax method to call your web service. This method allows you to supply a function that runs when the AJAX request succeeds . The code that runs on success takes the screen out the “busy” mode by completing the promise operation. The code then calls the showMessageBox method to display the result from the web service. If the server returns a “404 not found” message, or if the process encounters some other type of error, you can handle this condition by supplying an error function to your jQuery’s ajax call . The definition of the error function contains three parameters. In the event of an error, the third parameter, errorThrown, allows you to access the textual part of the HTTP status such as “Internal Server Error” or “Not found.” The code in the error function calls the promise operation’s error method and passes control of your application back to the LightSwitch runtime.

Sending Messages from Desktop Applications In this section, I’ll show you how to call the email service from a desktop application. I’ll describe how to recreate the Issue screen that I showed you in the HTML client sample. As before, this screen will allow the user to forward the contents of an issue record to an email recipient. The first step is to add a service reference from your project. To do this, run your application so as to start your web service. Now, stop the debugger. When you do this, your web service will continue to run in the background. Now, right-click your client project and select the “Add Service Reference” option. When the

580

Chapter 18 ■ Sending Email

Add Service Reference dialog opens, enter the URL to your web service and click on the Go button. The address you use should point to your SVC endpoint (for example, http://localhost:15340/MailService.svc). This populates the Services and Operations boxes that are shown in Figure 18-6. Set the value of the Namespace text box to MailService and click on the OK button.

Figure 18-6.  Adding a service reference After you add a service reference, you can call your web service from .NET screen code. To build a screen that calls your web service, open (or create) a detail screen for the issue entity. Just like in the HTML client example, use the Add Data Item dialog to add a property called Recipient. Add a button called Send Email, and add the code that’s shown in Listing 18-7.

581

Chapter 18 ■ Sending Email

Listing 18-7.  Screen code to send an email via a web-service call

582

Chapter 18 ■ Sending Email

583

Chapter 18 ■ Sending Email

Just like the HTML sample, this code sets your web service’s endpoint address in code. This makes it easier for you to deploy your application, because there’ll be no need to configure the address of your service endpoint. The code accomplishes this by finding the address of your XAP file and stripping off the trailing part of the address that contains DesktopClient/HelpDesk.Client.xap . It then uses the root part of the URL to build an address that points to your MailService.svc endpoint . Notice how the address ends with the suffix soap. This is because endpoint value in the web.config file configures this address as a SOAP/ XML-based endpoint. The next line declares a proxy to your web service . Next, the code defines the logic that runs when the web-service call succeeds . Finally, the line toward the end of the method calls your web service’s SendMail method asynchronously . This completes your screen, and you can now run your application. When you open an Issue screen, you can click the Email button to forward the contents of the record to an email recipient. If your code fails to connect to your web service at runtime, try to create your proxy by calling the nonoverloaded constructor (for example, New MailService.MailServiceClient()). This applies the endpoint address that you specified in the Add Service Reference dialog. This can help you diagnose the problem preventing you from establishing a connection. Another method you can use to diagnose problems is to enable application tracing and to view the trace results when your web-service connection fails. You can enable tracing by setting the Microsoft.LightSwitch.Trace.Enabled value to true in your web.config file. As I mentioned earlier, the Windows Event Viewer is another tool you can use to help diagnose errors.

■■Note  For desktop applications, you can only connect to web services that originate from the same web server. The default Silverlight client policy imposes this restriction for security reasons.

584

Chapter 18 ■ Sending Email

Sending Mail with Microsoft Outlook In the final part of this chapter, I’ll show you how to send messages by automating Microsoft Outlook. This technique is entirely client based, and unlike the previous example, it requires no server-side coding. In this example, I’ll show you how to add a button to an Issue Detail screen. When a user clicks this button, the code will create an Outlook message and use the issue data to compose the body of the message. The process leaves the Outlook message open on the screen and enables the user to review and send the message. A benefit of this technique is that you can use the Outlook API to automate other features in Outlook. For example, you could create tasks, calendar items, and other workflow items at the same time as you create your message. Another useful feature is that any messages a user sends from Outlook will appear in the Sent Items folder. Just as in the previous example, we’ll build a reusable class library that we can use throughout our application. To create the helper class, create a new class in your client project and add the code that’s shown in Listing 18-8. As before, you can add your code to a folder called UserCode to keep your project tidy. Listing 18-8.  Client-side COM code to create an Outlook message

585

Chapter 18 ■ Sending Email

586

Chapter 18 ■ Sending Email

587

Chapter 18 ■ Sending Email

This class defines a method called CreateEmail . This is the method that you would call to create an Outlook message. COM automation works only for desktop applications, so the first part of the code checks that your application is configured to run as a desktop application, rather than as a browser application . The next part of the code obtains a reference to the Outlook application . If Outlook is already open, it uses COM’s GetObject method to obtain a reference to the existing instance of Outlook. Otherwise, it uses the CreateObject method to create a new instance of Outlook. The next part of the code calls the Outlook API’s CreateItem method to create a new mail message . Just like the SMTP helper method that you created in Listing 18-1, the code tests for the existence of an HTML tag . If this tag exists, the code sets the format of the mail message to HTML. The next section of code sets the message body, subject, and recipient address. Finally, the code saves the email message  and calls the Display method to show the message contents in a new message window . At this point, the user can review the message and manually click on the message’s Send button to complete the send. If you want to send the email without any user intervention, delete the call to the Display method and call the message’s Send method instead. The final step that remains is to call your CreateEmail method from a screen. Open the IssueDetail screen from earlier and add a button called SendWithOutlook. This screen should include a local email address property called Recipient, which you added in the previous section. Now, add the code that’s shown in Listing 18-9.

588

Chapter 18 ■ Sending Email

Listing 18-9.  Screen code to create an Outlook message

This code in the SendWithOutlook method calls the CreateEmail method and supplies the email address, subject, and message body values that are shown on the screen . This code also implements the SendWithOutlook_CanExecute method . The purpose of this code is to disable the SendWithOutlook button if the application isn’t running on the desktop. Figure 18-7 illustrates how this screen appears at runtime.  

589

Chapter 18 ■ Sending Email

Figure 18-7.  Clicking the Send Email button creates an Outlook Message

■■Tip  Although this chapter focuses on email, you can automate Outlook in many other ways. By using similar code, you could create some powerful applications. For example, you could create Outlook appointments, contacts, or tasks via your LightSwitch application.

Summary This chapter showed you three ways to add email support to your LightSwitch application. I’ve showed you how to send email notifications, how to send emails from both desktop and HTML client screens, and how to automate Microsoft Outlook. At the beginning of this chapter, I showed you how to create a reusable email method that you can use throughout your application. This method sends messages by calling the objects in the System.Net.Mail namespace. In order to send messages, you need access to a SMTP mail server. This technique requires you to store your email credentials somewhere in your application, and I showed you how to use configuration settings to store the values in your web.config file. The first technique I showed you calls code to send messages when a change in data occurs. You can use this technique to send email notifications and alerts. To demonstrate this, I described how you can send a message when the status of an issue changes to “closed.” To implement this method, you would write code that handles the updating event of a record. The code you add here checks the status of the record and calls the helper method to send a message if appropriate. Most likely, there will be scenarios when you want to send a message irrespective of changes to data. To handle this scenario, I showed you how to build a WCF web service to send email messages. I then showed you the corresponding code to call this service from HTML client and desktop applications. This web service provides both SOAP- and REST-based methods. The REST-based method is designed for HTML client applications. With HTML client applications, you can easily call REST-based web services by using jQuery’s ajax method. With desktop applications, the SOAP-based method allows you to add a service reference to your web service from your client project. A service reference allows you to call web-service methods through a strongly typed proxy object that includes IntelliSense support. In the final part of this book, I showed you how to create email messages by automating Microsoft Outlook. This technique is ideal for users who spend a lot of time in Outlook. By using COM automation, you can also assist the workflow process by creating tasks or calendar items in code.

590

Part VII

Extending LightSwitch

Chapter 19

Creating Control Extensions LightSwitch includes an extensibility framework that you can use to extend the capabilities of the design environment. By installing third-party extensions, you can add additional controls, screen templates, data sources, and business types to Visual Studio. I’ll begin this chapter by showing you how to install and use third-party extensions. Next, I’ll show you how to build custom control extensions. The topics that I’ll cover in this chapter include the following: •

how to install extensions that are designed for previous versions of LightSwitch



how to build and deploy control extensions



how to enable developers to configure your control extension by extending the property sheet that appears in Visual Studio’s screen designer

There are several control types that you can build. For viewing and editing data, you can develop controls that bind to either scalar or entity values. The remaining control types are custom layout and command type extensions. To demonstrate these, I’ll show you how to build the following control extensions: time duration, combobox, toggle layout, and button control.

Using LightSwitch Extensions I’ll begin by showing you how to use extensions that other people have created. Then, I’ll show you how to build custom control extensions. And in the next chapter, I’ll show you how build screen template, data source, and business type extensions.

Installing LightSwitch Extensions Because LightSwitch 2015 is a recent product, few third-party extensions exist for this release. However, many great extensions exist for earlier versions of LightSwitch, and with a little bit of effort, you can make these extensions work with LightSwitch 2015. To demonstrate this technique, I’ll show you how to install and use the many-to-many control from Microsoft. You first need to download it from the following web page: http://code.msdn.microsoft.com/Many-to-Many-Control-for-52cd8c6c Visual Studio extension files end with a VSIX file extension. Inside the many-to-many control download package, you will find a file called ManyToManyControls.vsix in the binaries folder. To install an extension, simply double click the VSIX file in Windows Explorer.

593

Chapter 19 ■ Creating Control Extensions

Figure 19-1.  Error when you try to install an extension for an earlier version When you attempt to install the many-to-many control extension on a computer with only Visual Studio 2015, the installation fails. This is because the extension is designed for Visual Studio 2010. A method you can use to overcome this problem is to modify a setting in the manifest file that specifies the compatible versions of Visual Studio. This technique works for most extensions, but you should apply it with caution, as it isn’t guaranteed to work with all extensions. To carry out this change, rename the ManyToManyControls.vsix file to ManyToManyControls.zip. You can do this because VSIX files are simply compressed zip files with a VSIX extension. Next, extract the contents of this zip file. The root folder of this archive contains a file called extension.vsixmanifest. Open this file in Notepad and add an entry for the Visual Studio (version 14) Pro Edition into the supported products section, as shown in Figure 19-2.

Figure 19-2.  Modifying the manifest file

594

Chapter 19 ■ Creating Control Extensions

Save your changes and recompress the contents into a new zip file. When you compress your files, make sure not to add the parent folder into your archive. The extension.vsixmanifest file needs to be in the root of the archive. Finally, change the extension of your zip file to VSIX. At this point, you can install the extension by double clicking the VSIX file. After you install your extension, an entry will appear in the Visual Studio’s Extensions and Updates dialog, which you can open through the Tools menu. Figure 19-3 illustrates this dialog.

Figure 19-3.  Extensions and Updates dialog To use an extension in your LightSwitch project, you need to enable it in the properties of your project. On the Extensions tab (shown in Figure 19-4), use the checkboxes to enable the extensions that you want to use. You can also select the “Use In New Projects” checkbox to automatically enable the extension in any new projects that you create. This saves you from having to go to the Extensions tab and manually enable the extension each time you create a new project.

Figure 19-4.  Enabling extensions in your LightSwitch project

595

Chapter 19 ■ Creating Control Extensions

Using the Many-to-Many Data Control Once you install the many-to-many control, you can use it on your screens like any other built-in control. I’ll now demonstrate how to adapt the Engineer Details screen to enable managers to assign skills to engineers. To set up your application, carry out the following steps: 1. Create the two tables: Skills and EngineerSkills. Create the relationships between these two tables, and also create the relationship between the EngineerSkills and Engineer tables. You can refer to Chapter 2 for full details. 2. Create an Editable Grid screen for the Skills table. This enables you to enter skill records at runtime. After you create your table structure, create an Engineer Details screen. In the Add New Screen dialog, make sure to include the EngineerSkills data by selecting the “Engineer Skills” checkbox in the Additional Data section. In the screen designer, drag the EngineerSkills collection onto your screen. By default, LightSwitch displays this data collection using a data grid. Use the drop-down box to change this data item from a data grid to checkbox list.

Figure 19-5.  Using the many-to-many control That’s all there is to using a custom control. You can now run your application. Figure 19-6 shows what the control looks like at runtime.

Figure 19-6.  Many-to-many control as shown on screen at runtime

596

Chapter 19 ■ Creating Control Extensions

The many-to-many control is just one of many extensions available from the LightSwitch team. Let’s look at a couple of other useful extensions that you can add to your application. Just like the previous example, you would need to modify the manifest file to make these compatible with LightSwitch 2015. •

Filter Control: This control makes it really simple for you to create a custom search screen: https://code.msdn.microsoft.com/Filter-Control-for-eb947bdc



Excel Importer: This extension allows you to add a control to your screen that allows users to import data from an Excel spreadsheet: http://code.msdn.microsoft.com/ Excel-Importer-for-Visual-61dd4a90

Preparing Your Computer to Develop Extensions The software that enables you to develop your own extensions is the LightSwitch Extensibility Toolkit. At the time of writing (October 2015), a version of this toolkit was not yet available for Visual Studio 2015. I had hoped that Microsoft would release a 2015 prior to the publication of this book. In the absence of a 2015 version, I’ll instead show you how to build extensions with the 2013 version of the toolkit. Because of this, an unfortunate prerequisite of this chapter is that you need to install Visual Studio 2013. However, when Microsoft releases the Extensibility Toolkit for Visual Studio 2015, this step will not be necessary. After you install Visual Studio 2013, you will need to install the Visual Studio SDK. You can download this and the Extensibility Toolkit from the following web pages: •

Visual Studio SDK: https://www.microsoft.com/en-gb/download/details. aspx?id=40758



Extensibility Toolkit: https://visualstudiogallery.msdn.microsoft. com/2d204191-90eb-4dfb-831f-cf31513cef06

To install the Extensibility Toolkit, you first need to run the Extensibility Toolkit VSIX file. To complete the installation, copy a file called Microsoft.LightSwitch.Toolkit.targets into your MSBuild folder. The Extensibility Toolkit’s readme file provides full instructions. When you complete this step, you will be able to create new Extension Library projects in C# and VB through Visual Studio’s New Project window (as shown in Figure 19-7).

Figure 19-7.  Adding a new Extension Library project

597

Chapter 19 ■ Creating Control Extensions

When you create an Extension Library project, the template adds seven individual projects to your solution. The LSPKG project is the entry point that enables you to add new extension items to your project. To add a new item, right-click the LSPKG project and select the “Add New Item” menu item (shown in Figure 19-8). This opens the Add New Item dialog, which you can use to create one of the six extension items. You’ll use this dialog throughout this and the next chapter to create extension items.

Figure 19-8.  Right-click the LSPKG project to create a new item In addition to the LSPKG project, there are other projects in an Extension Library solution: •

Client: This contains the Silverlight custom control XAML and .NET code.



Client.Design: This contains custom code that extends the Silverlight runtime designer.



Common: This contains the lsml metadata that describes your extension and the common .NET code that runs on both the client and server.



Design: This contains custom code that extends the Visual Studio design surface. This project also stores custom screen templates.



Vsix: This contains the build output that developers can use to install your extension.

Understanding Custom Control Types There are five custom control types that you can create, which are shown in Table 19-1. You’ll be familiar with these control types because you will have used controls that match these control types throughout your day-to-day use of LightSwitch.

598

Chapter 19 ■ Creating Control Extensions

Table 19-1.  Custom Control Extension Types

Control Type

Purpose and Example Control

Value

Represents a single scalar value (text box, label)

Details

Represents an entity (auto-complete box)

Command

A control that initiates an action (button, hyperlink)

Collection

Represents a collection of data (data grid)

Group

A container for other controls (rows layout)

Let’s look at a high-level overview of how to create a control extension. The first step is to right-click your LSPKG project and select the option to add a new item. The subsequent tasks that you then need to complete are: 1. Set the control type, display name, and description for your control extension. 2. Specify the data types that your control supports (for collection and value types only). 3. Write the XAML that defines the UI for your control. 4. Set the icons for your control. After you create a custom extension, you can extend it further by adding custom properties and property editors. An example of custom properties are the “Show As Link” and “Target Screen” properties in Visual Studio’s property sheet for the label control. You can also add read-only support, handle keyboard navigation, and allow developers to access your control in code.

Creating Value Controls Value controls enable users to view or edit a single value. In this section, I’ll show you how to wrap the duration control from Chapter 13 in a custom control extension. You’ll find out how to allow developers to access your control in code and how to optimize the performance of your control when a developer uses it on a data grid. To build the duration editor control extension, carry out the following steps: 1. Start Visual Studio, create a new Extension Library project, and name it ApressExtension. 2. Right-click your LSPKG project, create a new control item, and name it DurationEditor.xaml. 3. Right-click your Client project, select the “Add Reference” option, and add a reference to the ApressControls.dll assembly that you created in Chapter 13. 4. Modify your DurationEditor.xaml file as shown in Listing 19-1. After you complete step one, Visual Studio opens your XAML file in the code editor window. The Add New Item dialog creates a custom control that includes a textbox control. If you want to build a very simple control, you can create a control extension that uses a textbox control rather than the duration control from the ApressControls.dll assembly.

599

Chapter 19 ■ Creating Control Extensions

Listing 19-1.  XAML markup for a value control

The XAML in this listing defines the presentation logic for your custom control and contains the following functionality: •

Support for the duration editor control: This code includes the duration editor control, although, as I mentioned earlier, you can use a textbox control instead to shortcut this example.



State handling: LightSwitch can hook into your control and show loading and error states. When a user enters invalid data in a screen, LightSwitch displays a red border around your control. This example includes the logic that supports this behavior.



Data-grid optimization: If you add this control to a data grid, the control appears in read-only mode and becomes active only when the user selects the cell.

The first part of this XAML adds a namespace reference to the ApressControls.dll assembly . This allows you to use the duration editor in your control. The second reference  refers to a value converter that converts integer durations into their hour and minute representations. We haven’t yet created this value converter, so at this moment, Visual Studio highlights this line as an error. The reference to the Microsoft.LightSwitch.Presentation.Framework assembly  allows LightSwitch’s state-handling mechanism to work. Note that namespace references must not contain line breaks. I added line breaks in these listings to allow the code to fit the page. For LightSwitch’s state handling to work correctly, you must enclose the contents of your control inside a StatesControl element . The main part of this control defines a duration editor control. It uses the data-binding path of Value to set the Duration dependency property . Value represents the data context value of your custom control

600

Chapter 19 ■ Creating Control Extensions

(that is, the value of the data item that your custom control binds to). The code also data binds the tooltip of the duration editor control to the description of your data item. The UserControl.Resources tag  defines the value converter that converts integer durations into a format that includes hours and minutes. At the moment, there isn’t any XAML in this control that uses this value converter. I’ll show you how to use this value converter later when we optimize this control for data-grid use. At present, you’ll also receive an error on this line, because it refers to the value converter that we’ll create very soon.

■■Note  The XAML examples in this book feature the VB version of the source code, and the listings refer to the namespace ApressExtensionVB. If you recreate these examples in C#, make sure to replace the references that include a VB suffix with the correct name.

Specifying Which Data Types to Support Value custom controls work with specific data types, and, in our case, the duration editor will work only with numeric data. You define the data types that your custom control supports in an LSML file that corresponds with your control. You can find this file in the Metadata folder of your Common project. To configure your control to work only with integer data, open the DurationEditor.lsml file and modify the SupportedDataType element as shown in Listing 19-2 . Listing 19-2.  Specifying control data types

If you want your control to support additional data types, you can specify this by adding additional SupportedDataType elements. The SupportedDataType values you can use include :String, :Boolean, and :Date. Appendix B shows a full list of valid values that you can use.

Supporting the FindControl Method Developers expect to be able to access the underlying Silverlight control in screen code by calling the IContentItemProxy object’s FindControl method. Refer to Chapter 9 if you want to remind yourself how this works.

601

Chapter 19 ■ Creating Control Extensions

To add support for the FindControl method, open the code file for your control. (You can do this by opening the DurationEditor.xaml file in the editor and choosing the right-click “View Code” option.) Now, edit the code by adding the code that’s shown in Listing 19-3. Listing 19-3.  Adding support for the FindControl method

602

Chapter 19 ■ Creating Control Extensions

When you add a control item, the Add New Item dialog creates two classes in your custom control’s code file: a class that represents your user control, and a supporting factory class. The code in Listing 19-3 modifies your user control class to implement the IContentVisual interface . The next block of code implements the Control property. The Control property returns a reference to your Silverlight control, and, in this example, DurationControl  refers to the name of the duration editor control that you defined in Listing 19-1. With VB.NET, Visual Studio now shows a warning against the reference to DurationControl. You can safely ignore this warning. This warning occurs because the project has not been built yet, and Visual Studio therefore does not recognize DurationControl. If you were writing a control that contains hidden UI elements (for example, an expander control), the Show method  would include code to reveal the hidden content. Because this doesn’t apply to our example, this code raises an exception if a developer attempts to call the Show method.

Setting the Control Icon By default, LightSwitch’s screen designer identifies your custom control with a green spherical icon (as shown in Figure 19-9). The Extension Toolkit’s control template generates a PNG icon file for every custom control that you create and names it after your control.

Figure 19-9.  Default green icon You can change this icon by replacing the DurationEditor.png file in your Design project in the following path: ApressExtensionVB.Design\Resources\ControlImages\.

Optimizing Controls for Data-Grid Use If you add the control that you’ve built so far to a data grid, LightSwitch creates an editable instance of your control on every row (see Figure 19-10). There are three problems with this behavior. First, it doesn’t match the default behavior of the standard LightSwitch controls. In Figure 19-10, notice how the grid displays the entry date as a read-only piece of text and how the control becomes editable only when the cell has the focus. The second relates to performance—it isn’t efficient to show multiple editable controls on every row in a data grid. And the final problem relates to usability. Each editable control introduces a tab stop. If the user isn’t using a mouse and attempts to navigate your screen with the keyboard, the process can be very awkward. Let’s suppose your data grid contains 45 records (the default page size), and a user sets the focus to the first row in the grid. To get to the Save button that appears after the grid, the user would have to press the tab key 90 times!

603

Chapter 19 ■ Creating Control Extensions

Figure 19-10.  The duration control is shown as editable for each row Because of these problems, it’s good practice to develop custom controls that display read-only text values when they appear on a data grid. To do this, you would create a display-mode template with XAML that shows your data through read-only controls. You define this template by setting the return value of a method called GetDisplayModeDataTemplate. You can find this method in the factory class for your control. Before you write your display-mode template, you need to create a custom Silverlight control to display the duration data with a Silverlight textblock control. In your Client project, add a new Silverlight user control in your Presentation > Controls folder and name it DurationViewer.xaml. Now, modify the contents of this control, as shown in Listing 19-4.

604

Chapter 19 ■ Creating Control Extensions

Listing 19-4.  Creating a display mode control

The custom control in Listing 19-4 displays the duration text in a textblock control . It uses the data-binding path Value to bind the Text property to the underlying content item. The data-binding definition specifies a value converter  to convert the integer duration values to a string value that consists of hours and minutes. For example, it converts the integer value 90 into the string value 1hr 30min. The code in the top section of the control defines the value converter . To create this value converter, create a new class called SplitMinutes in the Presentation ➤ Controls folder of your Presentation project. Make sure to add your class file to the Presentation ➤ Controls folder. If you fail to do this, your code might not compile properly. Now, add the code that’s shown in Listing 19-5.

605

Chapter 19 ■ Creating Control Extensions

Listing 19-5.  Value converter that returns a string representation of a time duration

606

Chapter 19 ■ Creating Control Extensions

This code contains the standard logic that exists in a value converter. If you need help understanding how this code works, you can refer to Chapter 13 for further help. Once you create your duration viewer control and SplitMinutes value converter, open the code file for your duration editor control. Now, add the code from Listing 19-6 to the IControlFactory Members region of your file. Listing 19-6.  Returning a read-only display-mode template

607

Chapter 19 ■ Creating Control Extensions

The first part of this code defines a constant variable called DisplayModeControlTemplate . This variable stores the template that the control uses when it renders in display mode. The XAML in this template presents your data with the duration viewer control that you created in Listing 19-4. In simpler scenarios, you could create a DisplayModeControlTemplate that displays your data with a textblock control and save yourself the effort of creating a custom viewer control. In this scenario, however, defining the logic in the duration viewer control keeps your code more self-contained and allows you to more easily reference value converters. GetDisplayModeDataTemplate  is the method that LightSwitch uses to retrieve the display-mode template. Your code file already includes this method, but, by default, it returns a null. The code that you add creates a DataTemplate object based on the content of the DisplayModeControlTemplate variable. To further improve performance, the code caches the DataTemplate in a variable called cachedDisplayDataTemplate. This completes the duration editor control. Figure 19-11 shows how it looks at runtime when you add it to a data grid. The screenshot illustrates the desired outcome. Notice that if a row doesn’t have the focus, the data grid shows the duration value by using the duration viewer control. Otherwise, it uses the editable control from the DurationEditor.xaml file.

608

Chapter 19 ■ Creating Control Extensions

Figure 19-11.  Display-mode template at runtime

Retrieving Height, Size, and Property Settings You can configure custom controls to apply the appearance settings that a developer sets through Visual Studio’s property sheet in the screen designer. These include height, size, and alignment settings. Listing 19-4 already implements this and uses data binding to apply the settings that the developer supplies. Listing 19-7 highlights the specific code that does this. Listing 19-7.  Binding to values that the developer enters in the screen designer

This code binds the size, alignment, and text values of the control to the values that the developer enters through the properties sheet. The code uses the following syntax to retrieve the width setting: Properties[Microsoft.LightSwitch:RootControl/Width] . RootControl refers to the control that every custom control inherits as its top-most base control. Width refers the width setting that the developer enters through the properties sheet. The remaining lines of code bind the height and alignment properties with similar syntax. The code that defines the textblock control binds the TextAlignment setting to the value that the developer enters in the properties sheet, as shown in . The full list of data-binding keys that you can use is shown in Appendix C.

609

Chapter 19 ■ Creating Control Extensions

Running and Deploying Your Extension You’ve now completed all of the tasks that are necessary to create a non-trivial control extension—well done! You can now run and debug your project in the usual way by pressing F5. This starts an experimental instance of Visual Studio 2013 that you can use to create or open an existing LightSwitch application. You can then debug your extension as normal by placing break points in your extension code. If you need to modify the debug settings for this experimental instance, you can do so by opening the properties of your VSIX project and editing the details on the Debug tab. To deploy your extension, simply distribute the VSIX file from the output of your VSIX project. For this example, you can find the output file in the following location: ApressExtensionVB\ApressExtensionVB.Vsix\bin\Release\ApressExtensionVB.vsix. You can now install your VSIX file as you would any other extension. After you install your extension, remember to enable it in the properties window of your LightSwitch project. You can then use your duration control on your screens, as shown in Figure 19-12.

Figure 19-12.  Using the duration editor control Note that if you created your duration editor control in VB, you might need to carry out an additional step before you build your project for the first time. The problem is that the duration editor and duration viewer controls depend on the SplitMinutes value-converter class. Visual Studio will refuse to build the duration editor and duration viewer controls if you don’t first build the SplitMinutes class. The way to resolve this problem is to right-click the DurationEditor.xaml and DurationViewer.xaml files in Solution Explorer and to select the “Exclude From Project” item. Once you exclude these two files, build your project. When you complete your initial build (and compile the SplitMinutes class in the process), re-enable the DurationEditor.xaml and DurationViewer.xaml files by selecting the right-click “Include In Project” item. You can now carry on as normal.

610

Chapter 19 ■ Creating Control Extensions

Setting Product/Installation Attributes Custom extensions include attributes that appear during the installation of your VSIX file and also appear in Visual Studio’s Extensions and Updates dialog. These attributes include name, version, author, description, license details, icon, and a whole lot of others. You can set these values through a file called vsixmanifest that exists in the root of your VSIX project. Double-click this file to open the editor, as shown in Figure 19-13.

Figure 19-13.  Setting the properties of your extension To make your extension compatible with Visual Studio 2015, edit the entry that exists in the Install Targets tab. As Figure 19-13 shows, you can set versions 12.0 to 15.0 to be the versions of Visual Studio that are compatible with your extension. Notice how the Version Range setting begins with a square bracket and ends with a round bracket: [12.0,15.0). Although this may look strange, this is the syntax that you use to define a range, and there is therefore no mistake here.

Creating a Detail Control (ComboBox) Now that I’ve explained how to build a simple “value” custom control, let’s move on and look at how to create a detail control. A detail control enables users to view and select entities. The built-in detail controls that ship with LightSwitch include the auto-complete box and modal window picker controls. In this section, I’ll show you how to create a combo box control extension that’s based on the combo box example from Chapter 13. The main benefit of the combo box control is that it restricts the values that users can choose, unlike the auto-complete box control. The advantage of an extension over a custom control is

611

Chapter 19 ■ Creating Control Extensions

simplicity. You can add an entity to your screen and simply set the control type to ComboBox. There’s no need to add DLL references and no need to add specific data-binding code to your screen. Here’s a high-level overview of the steps to build a detail control: 1. Right-click your LSPKG project, create a new control item and name it ComboBox.xaml. 2. Set the control type to Details in the control’s LSML file and remove the Supported Data Types setting. 3. Write XAML that defines the UI for your control. 4. Add the dependency properties and .NET code that supports your control. The custom combo box control that we’ll build will allow developers to choose the screen query that populates the control. In addition, developers can also choose which property to display in each row of the combo box. Figure 19-14 shows the end result of this exercise. This screenshot shows the controls that a developer can use to enter these properties in the properties sheet.

Figure 19-14.  Combo box control at design time

Setting the Control’s Metadata After you create your combo box control item, open its corresponding LSML file (in the Common project) and make the modifications that are highlighted in Listing 19-8. The first change is to mark the control as a details control. To do this, set the SupportedContentItemKind attribute to Details . In Value-type controls such as the duration editor control, you can use the Control.SupportedDataTypes element to specify the data types that your control supports. Because detail controls work with entities rather than simple data types, you need to delete the entire Control.SupportedDataTypes XML block . To extend Visual Studio’s property sheet to include controls that a developer can use to set the screen query and display property values, you need to define two supporting properties. You define these properties by adding the two Control.Property elements that are shown in . Each Control.Property element includes additional attributes that you can configure. The purposes of these attributes are shown in Table 19-2.

612

Chapter 19 ■ Creating Control Extensions

Listing 19-8.  LSML settings for a details control

613

Chapter 19 ■ Creating Control Extensions

Table 19-2.  Property Attributes

Attribute Name

Purpose of Attribute

Name

The name that uniquely identifies your property.

PropertyType

Defines the data type of your property. The list of values you can use is shown in Appendix B.

CategoryName

Defines the group where the property will be shown (for example, General, Appearance, Sizing).

Attributes – DisplayName

This defines the label text that’s shown next to the data-entry control for your property in Visual Studio’s property sheet.

Attributes – Description

This defines the text that appears when a developer hovers the mouse over the data entry control for your property.

The next step is to define the user interface for your combo box control. To do this, add the XAML that’s shown in Listing 19-9 to your ComboBox.xaml file.

614

Chapter 19 ■ Creating Control Extensions

Listing 19-9.  XAML code for the combo box control

The XAML in this listing specifies the namespace DetailRoot . The purpose of this is to simplify the data-binding code that you’ll write later on. The next line of code defines the XAML that represents a System.Windows.Controls.ComboBox control . The next step is to write the .NET code that supports your custom control. The Extension Toolkit’s control-item template creates ComboBox and ComboBoxFactory classes in your Client project. Open your combo box control’s code file and modify the code as shown in Listing 19-10. Make sure to add the necessary Imports (VB) or using (C#) statements. Listing 19-10.  Combo box code file

615

Chapter 19 ■ Creating Control Extensions

616

Chapter 19 ■ Creating Control Extensions

617

Chapter 19 ■ Creating Control Extensions

618

Chapter 19 ■ Creating Control Extensions

619

Chapter 19 ■ Creating Control Extensions

The amount of code behind this control is significant. To make sense of it, you can separate the logic into four distinct sections: 1. Initialization of the control and the retrieval of property-sheet values 2. The definition of dependency properties 3. Code that handles changes when the property-sheet values change 4. Code that sets the combo box control’s selected value and item choices Let’s begin by examining the first two sections. This code relies on the two dependency properties: ComboDisplayItemProperty and ComboBoxQueryProperty. The purpose of these dependency properties is to enable the control to access the screen query and display item property values that the developer sets in Visual Studio’s property sheet. You’ll use the ContentItemProperty dependency property later in this chapter. You might wonder why it’s even necessary to use dependency properties. After all, you could simply retrieve your property-sheet values without using any dependency properties and save yourself a whole load of complexity, as well as reduce the code by about a third. The reason you need to use dependency properties is to support the Silverlight runtime designer. Developers can change the property-sheet values at runtime, and dependency properties enable your control to react to the changes that a developer makes at runtime. Let’s take a closer look at these two dependency properties. •

ComboDisplayItemProperty: This dependency property stores the Display Item property that the developer sets through Visual Studio’s property sheet. The control’s constructor data binds this dependency property with the property-sheet value . The definition of this dependency property  defines a value callback method called ComboDisplayItemChanged. This method calls the SetContentDataBinding  method, which builds the display data template that defines each row in the combo box. Building this data template in code rather than statically defining it in XAML enables the control to react to changes that a developer makes through the runtime designer. The next part of the code binds the selected item in the combo box to the value of the underlying data item .



ComboBoxQueryProperty: This dependency property stores the Combo Query property that the developer sets through Visual Studio’s property sheet. This defines the name of a screen query that populates the combo box’s ItemsSource. The control’s constructor data binds this dependency property with the propertysheet value . The definition of this dependency property  defines a value callback method called ComboQueryChanged. This method calls a method called SetComboContentDataBinding  that binds the ItemsSource of the combo box to the screen query.

■■Tip  Your combo box control will now compile and run. It’s possible to now build and install this extension, but we’ll carry on and extend the control further.

Finding the Summary Property for an Entity With a details custom control, you might want to implement functionality that uses the summary property of the entity that binds to your control. For instance, you might want to know this so that you can show the summary property value on your control.

620

Chapter 19 ■ Creating Control Extensions

At present, the screen designer’s properties sheet for the combo box control allows the developer to enter the display property that’s shown in each row of the combo box. For example, the developer could enter Surname, and the combo box would display the Surname value in each row. I’ll now show you how to modify your control so that if a developer doesn’t supply a display property, the control uses the summary property instead. The purpose of this example is to teach you how to determine the summary property for an entity. Here’s an overview of the steps that you’ll carry out to add this feature to your combo box control extension: 1. In your custom control code, create a dependency property that binds to the data context of your control. You will use this to determine the data type of the entity that your control binds to. The name of this dependency property in Listing 19-10 is ContentItemProperty. 2. Write a method that accepts an entity type as an input and returns the summary property. 3. Modify the UI on your custom control so that it uses the summary property if the developer fails to supply a display item property through the properties sheet.

Creating a Helper Class Let’s create a helper class to help with this task. This helper class defines methods that you’ll use later in this chapter. The methods in this class include: •

GetSummaryProperty: This method returns the summary property for an entity.



GetFirstEntityProperty: The developer may not have defined a summary property for an entity. This method returns the first property.



IsTextProperty: This method accepts a property and returns true if you can represent it as a string. For example, if you pass in a binary property, this method returns false.



GetBaseSystemType: This method returns the underlying data type of a business type. The purpose of this method is to support the IsTextProperty method.



GetTextPropertiesForEntity: This method returns a list of text properties for an entity.

To create your helper class, add a new class called CustomEditorHelper to your Common project and enter the code that’s shown in Listing 19-11.

621

Chapter 19 ■ Creating Control Extensions

Listing 19-11.  CustomEditorHelper class

622

Chapter 19 ■ Creating Control Extensions

623

Chapter 19 ■ Creating Control Extensions

624

Chapter 19 ■ Creating Control Extensions

625

Chapter 19 ■ Creating Control Extensions

The benefit of a reusable helper class is that you can reuse it in other projects in your LightSwitch Extension library. We created the CustomEditorHelper class in the Common project. We can reuse this class in the Client project (the project that contains your Silverlight combo box control) by linking to the file. To do this, right-click your Client project and choose the Add Existing Item option. When the File Browser dialog appears, select the CustomEditorHelper file from your Common project. Expand the drop-down list next to the Add button and choose Add As Link (as shown in Figure 19-15).

Figure 19-15.  Linking to your CustomEditorHelper class The final step is to modify the SetContentDataBinding method in your combo box control to take into account the summary property, as shown in Listing 19-12. Listing 19-12.  Combo box control code

626

Chapter 19 ■ Creating Control Extensions

627

Chapter 19 ■ Creating Control Extensions

The changes to the SetContentDataBinding method in Listing 19-12 are as follows: The code checks whether the developer specifies a display item in Visual Studio’s property sheet . If the developer hasn’t specified a display property, the code calls the helper class’s GetSummaryProperty method  to return the summary property of the entity that your custom control binds to.

Creating Custom Property Editors Your combo box control is starting to take shape. You added a feature that developers can use to configure the display property that each row of the control shows. And if the developer doesn’t supply a display property, your control uses the summary property of the underlying entity instead. Although the control works well, there’s still room for further improvement. At the moment, developers must use a textbox to enter the display property (as shown in Figure 19-16). This method of entering a display property name is difficult, because developers have to remember and enter the exact property names. Worst of all, if the developer makes a mistake, your custom control will throw an exception at runtime and break the application.

Figure 19-16.  By default, developers must use a textbox to set the display property In this section, I’ll show you how to customize Visual Studio’s properties sheet by modifying the combo display property data entry control so that it uses a drop-down box instead of a textbox. To fully implement this change, there are two areas to modify. The first is to customize the combo display property data entry control in Visual Studio’s property sheet. The second is to apply the same customization to the Silverlight runtime designer.

Customizing Visual Studio’s Property Editor When Microsoft released Visual Studio 2010, it wanted to demonstrate its confidence in Windows Presentation Foundation (WPF), and as a result much of Visual Studio is built with WPF. This includes the window management system that includes the toolbars, context menus, and status bar areas of the IDE. Therefore, the method of extending Visual Studio’s properties sheet involves building a WPF user control. As you’ve seen, the LSML file for your custom control contains the definition for your custom combo display property, along with the definition of any other custom properties that you create. The LSML file also allows you to specify the control that developers would use to edit your combo display property in the properties sheet. To use a custom editor, you’d specify the name of an editor class in your LSML file. (In the example that follows, you’ll name your editor class EntityPropertyDropdownEditor.) This is a class

628

Chapter 19 ■ Creating Control Extensions

that implements an interface called IPropertyValueEditorProvider and provides an implementation of a method called GetEditorTemplate. Now, imagine that you’ve installed your control extension and have added the combo box control to a screen. You’re in the screen designer, you’ve selected an instance of your combo box, and you now open your properties sheet. At this point, Visual Studio builds the property sheet by searching the combo box’s LSML file to work out what custom properties there are and what editor control it should use. By using the LSML metadata, Visual Studio finds out that your combo box’s combo display property is associated with the EntityPropertyDropdownEditor class. With this knowledge, Visual Studio calls the EntityPropertyDropdownEditor class’s GetEditorTemplate method, which returns a WPF control that plugs into Visual Studio’s property sheet. This WPF control contains a combo box that displays a list of properties for the underlying entity. The WPF control binds to an object that represents the property value, which is an object that implements the IBindablePropertyEntry interface. Figure 19-17 illustrates the process in the form of a diagram.

Figure 19-17.  Building the properties sheet Now that you understand how this works, here’s an overview of how you’d create a custom editor for your combo box control’s combo display property: 1. Add the required references to your project. 2. Create a link to the CustomEditorHelper class from your Design project. 3. Create the WPF user control that contains the drop-down list of properties. 4. Create a supporting editor class for your control (EntityPropertyDropdownEditor). 5. Add value converters to assist with data binding.

Preparing Your Project There are two tasks to carry out before you can create a custom control editor. The first is to add a reference to the Microsoft.LightSwitch.ExportProvider.dll file from your Design project. On a 64-bit operating system, you can find this file in the following location: C:\Program Files (x86)\Microsoft SDKs\LightSwitch\v5.0\Client\

629

Chapter 19 ■ Creating Control Extensions

If you fail to add this reference, Visual Studio produces the following compile-time error when you build your project: Cannot resolve dependency to assembly 'Microsoft.LightSwitch.ExportProvider'. The second task is to add a link to the CustomEditorHelper class from your Design project. Right-click your Design project and select the “Add Existing Item” menu item. Select the CustomEditorHelper file from your Common project and click the Add As Link button. This step enables you to call the methods that are in the helper class.

Creating a Custom Control Editor Let’s begin by building the WPF editor control that plugs into Visual Studio’s property sheet. To do this, create a new folder called Editors in your Design project. Create a WPF user control in this folder and name it EntityPropertyDropdown. Modify the contents of this file as shown in Listing 19-13. In the XAML code, set the parent namespace of your control to Editors . Add an XML reference to the Editors namespace as shown in . (Make sure to replace ApressExtensionVB with the correct namespace for your extension project.) Listing 19-13.  Editor control XAML

630

Chapter 19 ■ Creating Control Extensions

The initial part of this code  defines the font that the editor control uses. So that your editor control doesn’t look out of place, you can use fonts that match the fonts that the Visual Studio IDE uses. DesignTimeFontSize and DesignTimeFontFamily are design-time public-resource items that allow you to reference the font settings that the developer chooses in Visual Studio’s Tools ➤ Option menu. ComboBoxLabel  defines the label that shows your property name. In this example, your label would show the text “Combo Display Property.” Visual Studio binds your editor control to an IBindablePropertyEntry object. Entry.DisplayName is the binding path that retrieves the property name. ComboBox  defines the drop-down box that shows the entity’s properties The combo box’s ItemTemplate  defines the content that each row of the control displays. The code in this listing data binds the control to an IBindablePropertyEntry object with the help of the following three value converters: •

GetAllEntityPropertiesConverter: This returns a list of properties for an entity, and its purpose is to fill the combo box.



AppendSemiColonConverter: This appends a semicolon to the end of the display name label.



EmptyStringToSummaryConverter: This sets the display text of the empty string that appears at the top of the combo box to .

The next step is to create the .NET code for your custom editor control, as shown in Listing 19-14.

631

Chapter 19 ■ Creating Control Extensions

Listing 19-14.  Custom editor control code

Listing 19-14 contains the standard code that you find in any user control. The only change you need to make to this code is to change the namespace to Editors . The next step is to add the code that contains the value converters. To do this, create a new class in your Editors folder called CustomEditorValueConverters and add the code that’s shown in Listing 19-15.

632

Chapter 19 ■ Creating Control Extensions

Listing 19-15.  Value-converter code

633

Chapter 19 ■ Creating Control Extensions

634

Chapter 19 ■ Creating Control Extensions

635

Chapter 19 ■ Creating Control Extensions

636

Chapter 19 ■ Creating Control Extensions

The next step is to create the class that returns your WPF user control to Visual Studio. In the Editors folder of your Design project, create the EntityPropertyDropdownEditor class and add the code that’s shown in Listing 19-16. Listing 19-16.  EntityPropertyDropdownEditor class

637

Chapter 19 ■ Creating Control Extensions

638

Chapter 19 ■ Creating Control Extensions

EntityPropertyDropdownEditorProvider  is the component that Visual Studio uses to create a custom property editor. Make a note of the PropertyValueEditorName  attribute that you specify here. This is the unique “key” that associates this component with your custom property. When Visual Studio builds the property sheet for your custom control, it calls the GetEditorTemplate method  to generate the UI for your custom property. This method returns the contents of the ControlTemplate variable , a string constant that defines the XAML for the WPF control that you defined in Listing 19-13. If you named your WPF control differently, you’ll need to amend the contents of the ControlTemplate variable to take this into account. It’s important that you get this correct, because if you make a mistake, Visual Studio will freeze when a developer opens the property sheet for your control. When you extend Visual Studio’s property sheet, you can use the EditorContext member on the IBindablePropertyEntry object to access an additional Context object . This allows the property editor to store and access additional data. However, the Silverlight runtime designer doesn’t support the Context object, so it remains unused in this example. If you want to find out more, Chapter 20 will show how you can use the Context object to extend the property sheet for the table designer.

Linking Your Property with the Editor Your WPF editor control is now complete, and the final step is to associate it with your custom control’s ComboDisplayItemProperty property. To make this association, open your custom control and edit the UIEditorId attribute as shown in Listing 19-17. Listing 19-17.  Linking your property with your custom editor

639

Chapter 19 ■ Creating Control Extensions

The UIEditorId attribute  specifies the control that Visual Studio uses to present your property. This value (EntityPropertyDropdown) matches the PropertyValueEditorName value that you define in your EntityPropertyDropdownEditorProvider class (see Listing 19-16). If you omit this attribute, Visual Studio chooses the most suitable property editor for the data type of your property. See the following list of editors that you can use in the Microsoft.LightSwitch.Designers. PropertyPages.UI.CommonPropertyValueEditorNames class: •

BooleanEditor



CheckBoxEditor



CiderStringEditor



CodeCollectionEditor



CodeRuleLinkEditor



CollectionEditor



ColorEditor



DesignerCommandLinkEditor

Customizing the Runtime Designer Customizing Visual Studio’s property sheet is just one half of the story. Developers can also set property values by using the Silverlight runtime designer, so it’s equally important to apply the same customization to this part of your application. Fortunately, the steps to carry this out are similar to those in the previous example, and you can reuse the code that you’ve already written. In this section, you’ll carry out your work in the ClientDesign project. The purpose of this project is to implement customizations to the Silverlight runtime designer. Here’s an overview of the steps to carry out: 1. Create a link to your Common project’s CustomEditorHelper class from your ClientDesign project. 2. Create a link to your Design project’s CustomEditorValueConverters file from your Design project. 3. Create a Silverlight user control that contains your custom editor control. 4. Create a supporting editor class that returns your Silverlight editor control to the runtime designer. After you link the CustomEditorHelper and CustomEditorValueConverters classes from your ClientDesign project, create a new folder called Editors and add a Silverlight user control named SilverlightEntityPropertyDropdown.xaml. Now, modify the contents of this file, as shown in Listing 19-18.

640

Chapter 19 ■ Creating Control Extensions

Listing 19-18.  Silverlight custom editor control

When you added a custom editor to Visual Studio’s property sheet in the previous section, you did so by adding a WPF user control. To customize the runtime designer, you add a custom Silverlight control instead; you’ll notice that the code in Listing 19-18 looks almost identical to the code in Listing 19-13.

641

Chapter 19 ■ Creating Control Extensions

Listing 19-18 defines a custom editor that includes a textblock and a combo box. Your Silverlight editor control binds to an IPropertyEntry object, and you can reuse the value converters that you created in the previous example. Because you added a link to the CustomEditorValueConverters, which belongs in your Design project, you need to add a namespace reference to this project . In the header section, make sure to prefix the SilverlightEntityPropertyDropdown class with the Editors namespace in the x:Class attribute value. The textblock  control shows the custom property’s display name and uses the AppendSemiColonConverter value converter to append a semicolon to the end of the text (for example, ComboBox Display Property:). The combo box  uses the GetAllEntityPropertiesConverter to display the valid choices, and it uses the data-binding path of PropertyValue.Value to set the selected item. In the markup for your combo box, it’s very important to specify the ItemsSource property before the SelectedItem property. If you fail to do this, your control won’t correctly show the selected item. The next step is to create the .NET code for your Silverlight editor control, as shown in Listing 19-19. Listing 19-19.  SilverlightEntityPropertyDropdown code

The code in Listing 19-19 contains the Silverlight equivalent of the code from Listing 19-14. Once again, the important point is to set the namespace of the control to Editors . Now, create a new code file in your Editors folder of your Client.Design project and add the SilverlightEntityPropertyDropdownEditor class that’s shown in Listing 19-20.

642

Chapter 19 ■ Creating Control Extensions

Listing 19-20.  SilverlightEntityPropertyDropdownEditor class

643

Chapter 19 ■ Creating Control Extensions

644

Chapter 19 ■ Creating Control Extensions

SilverlightEntityPropertyDropdownEditor is the component that the runtime designer uses to load your custom editor. Like in the WPF example, you need to set the PropertyValueEditorName value  to match the UIEditor choice that you specify in your LSML file; this setting was shown in Listing 19-17. This completes the runtime designer sample. When you install and run your extension, you’ll be able to modify your combo box control’s display property through the runtime designer, as shown in Figure 19-18.

Figure 19-18.  Silverlight runtime designer

Creating a Group Control Extension In the next example, I’ll show you how to build a group extension. The purpose of a group control is to arrange child items in a custom way. The built-in group controls that ship with LightSwitch include rows layout and columns layout controls. As an example, I’ll show you how to create a control that includes a Show/Hide button. When the user clicks this button, the control toggles the visibility of the data items that appear inside the control. The steps to create this control are as follows: 1. Right-click your LSPKG project, create a new control item, and name it ToggleControl.xaml. 2. In your Client project, add a reference to the Microsoft.LightSwitch.Client. Internal assembly. The default location of this file on a 64-bit computer is C:\ Program Files (x86)\Microsoft SDKs\LightSwitch\v5.0\Client. You need this reference to support the content item presenter control that you’ll add to your custom control. 3. Modify your ToggleControl.xaml file by adding the contents from Listing 19-21. 4. Set the SupportedContentItemKind to Group in your control’s LSML file, and remove the supported data types.

645

Chapter 19 ■ Creating Control Extensions

Listing 19-21.  XAML for toggle control control

This control consists of two main parts: •

Logic that defines the Show/Hide button



Logic that arranges the child data items that the developer adds to the control

The first part of the XAML defines a textblock control that shows the display name . This allows the developer to set a title for the group control, and it can help users to identify the purpose of the controls that are shown within the control. The next line of code defines a button called ToggleButton . This button toggles the visibility of a StackPanel called ContentPanel . This panel acts as the parent container for the child items that are shown in the control.

646

Chapter 19 ■ Creating Control Extensions

The stack panel control contains an items control. This is a Silverlight control that binds to a data source, and it allows you to customize the appearance of each data item by defining a layout in an item template. You’ll notice that the items control defines a data source that specifies a binding string of ChildItems. This is because the underlying IContentitem object that the toggle control (and all other custom group controls) binds to exposes the child data items through a collection called ChildItems. ItemsPanel  allows you to define the parent control that contains the item template contents. The items panel template control specifies a StackPanel with its orientation set to vertical. This means that the toggle control displays the child items in rows layout style (that is, vertically stacked). If you want to lay out the child items differently, you can use a different layout control here. The controls that I described so far define the framework for your control. One task you still need to carry out is to define the controls that render your child data items. One way not to do this is to specify a textbox control in your item template. Although this can work, a textbox control isn’t the best control to display every single data item type. For example, your users won’t be too impressed if your group control uses a textbox to display an image. A much better approach is to use a special control called a content item presenter . This control renders the most suitable UI control for the bound data item. Note that Visual Studio may show the following error against the content item presenter control: “Cannot find a resource with the Name/Key ScreenLoadingBackgroundBrush.” Your control extension still works despite this error; therefore, you can safely ignore this warning. The final task is to add the .NET code that toggles the visibility of ContentPanel, shown in Listing 19-22. Listing 19-22.  Group control code

647

Chapter 19 ■ Creating Control Extensions

Setting the Visibility of Labels By default, LightSwitch displays a label next to any control that you add to a screen. Although this is very useful for controls such as textboxes and labels, you generally don’t want labels to appear next to group or custom controls. LightSwitch defines the label settings in the LSML file for your control, as shown in Listing 19-23. Listing 19-23.  LSML changes

Before you begin to modify the label properties, you should set the SupportedContentItemKind attribute to Group . This setting identifies your custom control as a group control. LightSwitch determines the label and other property settings through property-value inheritance. This process means that if a developer fails to set the Attached Label Position value for a data item, LightSwitch uses the Attached Label Position value of the parent control instead. If an attached label position isn’t set at the parent level, the resolution system carries on searching parent items until it finds a value. The default attached label position of a screen is left aligned. Unless a developer manually sets the attached label position, your group control will most likely inherit the default label position of left aligned. To prevent LightSwitch from displaying a label next to your group control, set the AttachedLabelSupport setting to DisplayedByControl . The other valid setting you can use is DisplayedByContainer. Although the DisplayedByControl setting hides the label that appears next to your group control, you still want labels to appear next to child items that appear inside your control. To do this, the LSML defines a ControlPropertyOverride element  to make certain that Visual Studio includes the attached label position control in the properties sheet for your group control. By allowing developers to set your group control’s attached label position, Silverlight’s Property Value Inheritance behavior will apply the label position to your group control’s child items. This completes the example, and you can now build and run your extension. Figure 19-19 shows screenshots of the final control.

648

Chapter 19 ■ Creating Control Extensions

Figure 19-19.  Toggle layout control In Figure 19-19, notice that your custom control doesn’t left align the address labels, and because of this, the appearance of this control looks a bit jagged. If you don’t like this appearance, you can create a rows layout beneath your toggle layout control and add your data controls beneath your rows layout.

Creating a Command Control Extension In the final section of this chapter, I’ll show you how to build a command extension. I’ll show you how to build a customized button with a green background. This control functions in the same way as the custom button that I showed you in Chapter 13. However, the big advantage of the command extension is that it provides a better implementation. The custom button in Chapter 13 contains a hard-coded reference to the screen method that the button calls. This imposes a dependency between the custom control and screen, and it results in an approach that isn’t very extensible. By creating a command extension, developers can data bind your custom button to the underlying screen method. Here are the steps to carry out this example: 1. Right-click your LSPKG project, create a new Control item, and name it HighlightButton.xaml. 2. Modify your HighlightButton.xaml file by adding the contents from Listing 19-24. 3. Set the SupportedContentItemKind to Command in your control’s LSML file, remove the Supported Data Types settings, and modify the default label settings.

649

Chapter 19 ■ Creating Control Extensions

Listing 19-24.  Custom button control code

The XAML in this listing defines a normal Silverlight button . This custom control enables the developer to set the dimensions of control by binding the presentation attributes such as width and height to the property-sheet values. The button template code enables you to specify the look of your control, and it defines the gradient green background color . The next step is to add the CustomButton_Click method to your CustomButton class, as shown in Listing 19-25.

650

Chapter 19 ■ Creating Control Extensions

Listing 19-25.  Custom button .NET code

You can access the underlying screen method through the Details member of the IContentItem object that binds to your control. This IContentItem object implements the IExecutable interface. You can simply call the ExecuteAsync method  to asynchronously call the method that exists in the code file of your LightSwitch screen. The next step is to make the necessary changes to your LSML file, as shown in Listing 19-26. Listing 19-26.  Custom button LSML file

651

Chapter 19 ■ Creating Control Extensions

The code in this listing sets the SupportedContentItemKind to Command  in order to identify the control as a command control. Just like in the preceding group control example, you want to hide the default label that LightSwitch displays to the left of your custom button. You can accomplish this by setting the AttachedLabelSupport attribute to DisplayedByControl . This completes the button control sample. Figure 19-20 shows screenshots of the final control.

Figure 19-20.  Custom button

Summary Extensions are installable components that extend the Visual Studio IDE and enable you to add extra capabilities to LightSwitch. Extensions are packaged into files with a VSIX extension. To install an extension, simply run the VSIX file. When the installation completes, your extension will appear in Visual Studio’s Extensions and Updates dialog. You can use this dialog to manage and uninstall extensions from Visual Studio. Before you can use an extension in a LightSwitch project, you have to enable it through the properties of your project. Many extensions exist for older versions of LightSwitch. If you find an extension that doesn’t install under Visual Studio 2015, you can fix this by modifying the compatibility settings in the manifest of the extension. Although this technique works with most third-party extensions, it isn’t guaranteed to always work. LightSwitch provides six extensibility types: business types, controls, data sources, screen templates, shells, and themes. In this chapter, I showed you how to create control extensions. In the next chapter (Chapter 20), I’ll show you how to create the remaining extension types. Unlike directly using Silverlight controls, as I showed you in Chapter 13, developers can more easily work with controls that they install through extensions. This is because if a developer wants to use a control extension on a LightSwitch screen, there’s no need to select the control assembly from a separate dialog and write custom data-binding code. Developers can simply use the data item’s drop-down menu in the screen designer to select the custom control. With extensions, you can also build controls that lay out items on a screen, just like the rows layout and columns layout controls that ship with LightSwitch. Another feature of control extensions is that you can build maintainable settings that developers can set through Visual Studio’s properties sheet.

652

Chapter 19 ■ Creating Control Extensions

There are five types of control extension that you can create: value, details, command, collection, and group. These control extension types match the control types that you see through day-to-day usage of LightSwitch. For instance, a value control displays a single value—just like a textbox or label. A details control displays an entity—just like an auto-complete box or modal window picker. To create extensions, you need to install the Visual Studio SDK and the Microsoft LightSwitch Extensibility Toolkit. You can download these components free of charge from the Microsoft website. The 2015 version of the toolkit was not yet available at the time of writing. Therefore, I showed you how to build extensions with the 2013 version of the Extensibility Toolkit. Once you set up your computer, you can add an Extension Library Project through Visual Studio’s Add New dialog. An Extension Library Project contains seven individual projects, one of which is an LSPKG project. The LSPKG project is the project that you use to add a new extension item. To add a new extension item, right-click your LSPKG project and select the “New Item” option. This creates all the files for your new extension. To complete your control extension, you can simply flesh out these files with the functionality that you want to add. The main file in a control extension is an XAML file (a Silverlight user control) that defines the UI for your control. A custom control binds to an IContentItem object on a LightSwitch screen, which enables you to use Silverlight data-binding techniques to bind the UI elements on your custom control to the underlying screen data item. The project stores the metadata for your control in a corresponding LSML file. You can use this metadata to set the control type (for example, value, details, collection, and so forth), display name, description, and data types that your control supports. To debug an extension, press F5 to start an experimental instance of Visual Studio. You can debug your extension project by adding breakpoints and opening a LightSwitch project through the experimental instance of Visual Studio. To demonstrate how to create a details control, I showed you how to build a combo box control extension. With this control, developers can set the data source and the data property that the combo box shows on each row. The developer can enter these settings through the properties sheet in the Visual Studio screen designer, or through the Silverlight runtime designer. Lets review the steps to add a control to the Visual Studio property sheet. The first step is to create a WPF user control. The reason you need to use WPF is because Visual Studio itself is built with WPF. The next step is to create an editor class that implements the IPropertyValueEditorProvider interface. This class must implement a method called GetEditorTemplate. The purpose of this method is to return the XAML markup that represents your WPF custom editor. The final step is to associate your WPF control with your custom control. You do this by configuring the UIEditorId setting in the control’s LSML file. You can customize the Silverlight runtime designer using a very similar process. The main difference is that you create a Silverlight user control rather than a WPF user control. Another topic that I covered in this chapter is how to access the summary property value of the data item that binds to a details control. If a summary property for this data item doesn’t exist, I showed you a fallback mechanism that returns the first text property, or the first property that LightSwitch can represent as a string. The next control type I described was the group control. The purpose of a group is to arrange child items in a custom way. To demonstrate this topic, I showed you how to build a group control that includes a Toggle button. The purpose of this button is to allow the end user to show or hide the items that appear within the control. To build a group control, the first step is to add an ItemsControl object to the XAML for your control. The ItemsControl object is a Silverlight control that binds to a group data item from a LightSwitch screen. You can customize the appearance of each child data item in the group by defining a layout in an item template. The item template contains a content item presenter control. You use this control to generate a control that most suits the data type of each child item.

653

Chapter 19 ■ Creating Control Extensions

The final control type I described was the command control. This type of control binds to the LightSwitch screen method. To demonstrate this control type, I showed you how build a button that features a green background. To build a command control, you add UI elements to the XAML to enable the end user to interact with your control. To call the screen method that your control binds to, you would use the Details member of the IContentItem object that binds to your control. The Details member exposes an IExecutable object. This object provides a method called ExecuteAsync, which is the method you would call to execute the underlying screen method. Finally, I showed you how to deploy and distribute your extension. To make your extension compatible with LightSwitch 2015, you need to amend the setting that controls the compatible version type in the manifest of your VSIX project. To deploy your extension, you can simply build your solution and run the output from your VSIX project.

654

Chapter 20

Creating Data and Presentation Extensions In the previous chapter, I introduced the topic of extension projects and showed you how to build control extensions. In this chapter, I’ll describe the remaining extension types that are available with the Extensibility Toolkit. Specifically, I’ll show you how to do the following: •

create business type and data-source extensions



create screen template extensions



create shell and theme extensions

At the start of this chapter, I’ll show you how to build a business type to store time-duration data. This business type will include custom validation and a custom control. Developers can configure this validation rule through the properties sheet in Visual Studio’s table designer. I’ll show you how to extend Visual Studio to support this functionality. Next, I’ll describe how to customize the look and feel of your applications by building shell and theme extensions. After this section, I’ll show you how to build desktop and HTML client screen template extensions. By building screen template extensions, you can automate the repetitive steps that you often carry out when you develop screens. In the final section of this chapter, I’ll demonstrate how to build a data-source extension that you can use to read data from the Windows event log.

Introduction This chapter relies on content that I covered in Chapter 19. So, to begin, here’s a summary of the most relevant points that apply to this chapter. At the time of writing, Microsoft had not released a version of the Extensibility Toolkit for Visual Studio 2015. Therefore, the content in this chapter relies on Visual Studio 2013 and the Extensibility Toolkit for Visual Studio 2013. A prerequisite of this chapter is that you install both of these components. Once you install the Extensibility Toolkit, you can add new Extensibility Solutions through Visual Studio’s “File ➤ New” menu item. An Extensibility Solution consists of seven separate projects. A notable project is the LSPKG project, because this is the project that you use to add new extension items to your solution. Another important project is the VSIX project. This project produces the output that you use to install your extension into Visual Studio. To build extensions that work with LightSwitch 2015, you must modify the Compatible Versions setting in the manifest file to include versions 14 or above of Visual Studio. With these points in mind, let’s now move on and look at the first extension type in this chapter: the business type extension.

655

Chapter 20 ■ Creating Data and Presentation Extensions

Creating a Business Type Extension Business types are special types that extend the basic LightSwitch data types. The business types that ship with LightSwitch include phone number, money, and web address. The benefit of a business type is that it encapsulates both validation and custom data entry controls. By building a business type extension, you can easily reuse the validation and custom control logic in multiple projects, and you can also easily share it other developers. To demonstrate, I’ll show you how to build a business type for time durations. This example reuses the duration editor control and includes additional validation. If a developer creates a table and adds a field that uses the duration type, the validation allows the developer to specify the maximum duration that users can enter into the field, expressed in days. Here’s an overview of the steps to build this example: 1. Create a new business type and set the underlying data type. 2. Create and/or associate custom controls with your business type. 3. Create an attribute that stores the maximum acceptable duration (for validation purposes). 4. Write the validation logic in the Common project. To create a business type, right-click your LSPKG project, select “New Item,” and add a new business type called DurationType. When you do this, the business type template does two things. First, it creates an LSML file that you can use to define your business type, and, second, it creates a new custom control for your business type. Our duration type uses the integer data type as its underlying storage type. This is defined in your business type’s LSML file, which you can find in the Common project. To define the underlying storage type, open the DurationType.lsml file in the Common project and modify the UnderlyingType setting, as shown in Listing 20-1 . Listing 20-1.  Creating a business type

The UnderlyingType values that you can specify include :Int32, :String, and :Double. Appendix B shows a list of acceptable values that you can use. The DisplayName property  specifies the name that identifies your business type in the table designer. Toward the bottom of the LSML file, the DefaultViewMapping  element enables you to specify the default control for your business type. By default, the template sets this to the custom control that it automatically creates. So, in this case, it sets it to DurationTypeControl.

656

Chapter 20 ■ Creating Data and Presentation Extensions

Although there’s still much more functionality that you can add, you’ve now completed the minimum steps that are needed for a functional business type. If you want to, you can compile and install your extension.

Associating Custom Controls with Business Types LightSwitch associates business types with custom controls. For instance, if you’re in the screen designer and add a property that’s based on the phone number business type, LightSwitch gives you the choice of using the phone number editor, phone number viewer, textbox, or label controls. Strictly speaking, you don’t configure a business type to work with specific set of controls. The relationship actually works in the other direction—you define custom controls to work with business types by adding data to the custom control’s metadata. When you create a business type, the template generates an associated control in your Client project’s Controls folder (for example, ApressExtensionVB.Client\Presentation\Controls\ DurationTypeControl.xaml). This automatically provides you with a custom control that accompanies your business type. Because you already created a duration control, you can save yourself some time by associating it with your business type. The association between custom controls and business types is defined in your custom control’s LSML file. To associate the duration editor control (discussed in Chapter 19) with your duration business type, open the LSML file for your control. You can find this file in the Metadata > Controls folder of your Common project. Find the Control.SupportedDataTypes node, add a SupportedDataType element, and set the DataType attribute to DurationType (as shown in Listing 20-2). DurationType refers to the name of your business type, as defined in the LSML file of your business type. Listing 20-2.  Specifying control data types

The code in Listing 20-2 configures the duration editor control to support integer and duration data types. You can add additional SupportedDataType entries here if you want your duration editor Control to support extra data types.

Enforcing Validation The benefit of business-type validation is that LightSwitch applies your validation logic, irrespective of the control that you use on your screen. For desktop applications, business-type validation runs on both the client and server. Therefore, business-type validation code belongs in the Common project. In this section, I’ll show you how to create a validation rule that allows developers to specify the maximum duration in days that users can enter. You can allow developers to control the behavior of your business type by creating attributes that LightSwitch shows in the table designer. Custom attributes are defined in a business type’s LSML file, and you’ll now create an attribute that allows developers to specify the maximum duration that an instance of your business type can store. Open the LSML file for your business type and add the parts that are shown in Listing 20-3.

657

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-3.  Extending the metadata to support a maximum duration

The code in Listing 20-3 defines two things. It associates validation logic with your business type, and it defines an attribute that allows developers to specify the maximum duration that an instance of your business type can store. Let’s now look at this code in more detail.

658

Chapter 20 ■ Creating Data and Presentation Extensions

Associating Validation Logic with a Business Type To associate your business type with validation logic, there are two tasks that you need to carry out in your LSML file. The first is to define an AttributeClass, and the second is to apply the class to your business type. The code in Listing 20-3 defines an AttributeClass  that includes the Validator attribute . It includes an attribute that defines the data type that the validation applies to , and the value that you specify here should match the name of your business type. After you define your AttributeClass, you need to define an Attribute for your business type . When you write this code, there are two important naming rules you must adhere to: •

Your AttributeClass name  must match your Attribute’s Class value .



Your Attribute’s Class value  must be preceded with @ symbol.

If you don’t abide by these naming conventions, your validation simply won’t work. You’ll notice that the name of the class is MaxIntegerValidationId, and by the end of this section, you’ll notice that you don’t write any .NET code that creates an instance of the MaxIntegerValidationId class. Technically, MaxIntegerValidationId is a class that exists in the model’s conceptual space rather than in the .NET code space. In practice, it’s easier to think of MaxIntegerValidationId as a string identifier, and for this reason, this example names the class with an Id suffix to allow you to more easily follow its usage in the proceeding code files.

Defining Property Sheet Attributes The code in Listing 20-3 defines an attribute that controls the maximum duration that an instance of your business type can store. To define an attribute, you need to add an AttributeProperty  to your AttributeClass. Once you do this, you can define additional attributes  that control the way that your attribute appears in the table designer. These attributes include •

DisplayName: Defines the label text that appears next to your property



Category: Specifies the group that your property appears in



UIEditor: Defines the editor that allows users to modify your property value. Chapter 12 contains a list of valid UIEditor choices.

Once you’ve defined your AttributeProperty, you’ll also need to define a Property that’s associated with your business type’s Attribute. This Property specifies the default value that your business type applies if the developer hasn’t set a value through the properties sheet .

659

Chapter 20 ■ Creating Data and Presentation Extensions

Figure 20-1 illustrates how this property appears in the table designer at runtime.

Figure 20-1.  Maximum Days attribute, as shown in the properties sheet

Applying Validation Logic Now that you’ve set up your LSML file to support custom validation, let’s take a closer look at how businesstype validation works. In the LSML for your business type, you used the identifier MaxIntegerValidationId. This identifier ties your business type with a validation factory. When LightSwitch needs to validate the value of a business type, it uses this identifier to determine the factory class that it should use. The factory class then returns an instance of a validation class that contains the validation logic for your business type. In our example, we named our validation class MaxIntegerValidation. This class implements the IAttachedPropertyValidation interface, and it implements a method called Validate. This is the method that LightSwitch calls to validate the value of your business type. Figure 20-2 illustrates this process.

Figure 20-2.  Applying validation logic To apply this validation to your business type, let’s create the factory and validation classes. Create a new class file in your Common project and name it MaxIntegerValidationFactory. Now, add the code that’s shown in Listing 20-4.

660

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-4.  Creating the validation factory code

661

Chapter 20 ■ Creating Data and Presentation Extensions

662

Chapter 20 ■ Creating Data and Presentation Extensions

The first part of this code contains the identifier (AttributeClass) that links your validation factory to your LSML file . The syntax that you use is very important. You need to prefix the identifier with the namespace of your project, followed by the : symbol and the @ symbol. The remaining code in the validation factory performs validation to ensure that the data type of the model item matches your business type, and it returns a new instance of your MaxIntegerValidation class if the test succeeds. In the code that carries out this test, it’s important to specify your business-type identifier  in the correct format. It should contain the namespace of your project, followed by the : symbol, followed by the business type name. At this point, you’ll see compiler errors, because the MaxIntegerValidation class doesn’t exist. The next step is to create a new class in your Common project, name it MaxIntegerValidation, and add the code that’s shown in Listing 20-5. Listing 20-5.  Creating the validation class

663

Chapter 20 ■ Creating Data and Presentation Extensions

664

Chapter 20 ■ Creating Data and Presentation Extensions

The code in Listing 20-5 defines a class that implements the Validate method . LightSwitch calls this method each time it validates the value of your business type. You can use this method to retrieve the data value from the value parameter, apply your validation rules, and return any errors through the results parameter. The validation code retrieves the MaxDays attribute by querying the collection of attributes  that are supplied to the validation class by the factory. The code retrieves the first attribute and checks that it relates to your duration type. In the test that the code carries out, notice the syntax of the class ID . It should contain the namespace of your project, followed by the : symbol, followed by the @ symbol, followed by the validation identifier that you specify in your LSML file.

Creating Custom Property Editor Windows By default, the MaxDay attribute that you added to your business type shows up as a textbox in the table designer’s property sheet. In this section, you’ll learn how to develop a popup window for developers to edit custom attribute values. The phone number business type provides a great example of a business type that works just like this. As you’ll recall from Chapter 2 (Figure 2-8), this business type allows developers to define phone number formats through a popup Phone Number Formats dialog. The advantage of a popup window is that it gives you more space and allows you to create a richer editor control that can contain extra validation or other neat custom features. In this section, you’ll find out how to create an editor window that allows developers to edit the MaxDay attribute. The custom editor window will allow developers to set the value by using a slider control. Chapter 19 showed you how to customize the screen designer’s properties sheet, and this example works in a similar fashion. When you’re in the table designer and Visual Studio builds the property sheet for an instance of your business type, it uses the LSML metadata to work out what custom attributes there are and what editor control it should use. The LSML file allows you to specify a UIEditor for each custom attribute in your business type. The value that you specify provides an identifier that associates the attribute with a factory class. When Visual Studio builds the property sheet, it uses this identifier to find a matching factory class. It then uses the factory class to return an editor class that implements the IPropertyValueEditor interface. The editor class implements a method called GetEditorTemplate that returns the XAML that plugs into Visual Studio’s

665

Chapter 20 ■ Creating Data and Presentation Extensions

property sheet. To create a custom popup property editor, you’d return a piece of XAML that contains a hyperlink control that opens your custom property editor in a new window. Figure 20-3 illustrates this process.

Figure 20-3.  Creating a popup custom editor window You’ll remember from Chapter 19 that Visual Studio is built with WPF; therefore, creating a popup window that integrates with the IDE will involve writing a custom WPF user control. Just like the other examples in this book that extend the Visual Studio IDE, you’ll carry out this work in your Design project. To create the custom editor window, right-click your Design project, click “Add ➤ New Item,” and select “User Control (WPF).” Once your control opens in Visual Studio, modify the XAML as shown in Listing 20-6. Listing 20-6.  Creating a custom property editor

666

Chapter 20 ■ Creating Data and Presentation Extensions

This code defines the XAML for the window that opens from the properties sheet. Figure 20-4 shows how this window looks at runtime. The XAML contains a TextBlock that shows the selected Maximum Days value . The Slider control  allows the developer to edit the value, and because of the data-binding code that you’ve added, the TextBlock value updates itself when the developer changes the value through the slider control.

Figure 20-4.  The popup window that allows users to set maximum days

■■Caution  If you copy and paste the XAML in a WPF user control, your code might fail to compile due to a missing InitializeComponent method. See here for more details: http://stackoverflow.com/questions/954861/why-can-visual-studio-not-find-mywpfinitializecomponent-method

667

Chapter 20 ■ Creating Data and Presentation Extensions

Once you’ve added your WPF user control, add the code that’s shown in Listing 20-7. Listing 20-7.  Creating a custom property editor

668

Chapter 20 ■ Creating Data and Presentation Extensions

The code in Listing 20-7 configures your control to inherit from the Window class . By default, your WPF control inherits from the UserControl class. This code contains a dependency property called ValueProperty, which is of data type integer . This property enables the window to share the selected value with the code in the properties sheet that opens the window.

■■Caution  When you create dependency properties, make sure to pass the correct value to the UIPropertyMetadata constructor. For example, if you define a decimal dependency property and you want to set the default value to 0, use the syntax UIPropertyMetadata (0d). If you set default values that don’t match the data type of your dependency property, you’ll receive an obscure error at runtime that can be difficult to decipher. You’ve now created the window that allows the developer to edit the MaxDays attribute, and the next step is to define the UI that contains the hyperlink that opens this window. Create a new user control (WFP) called EditorTemplates.xaml in your Design project and add the code that’s shown in Listing 20-8. Listing 20-8.  Adding the UI that opens the custom window

The code in Listing 20-8 defines a Resource Dictionary that contains a single data template called MaxIntegerEditorTemplate . A Resource Dictionary gives you the ability to add additional templates at a later point in time. Make sure to configure the xmlns:self value so that it points to the namespace of your extension project . When you add a WPF user control, the template creates a .NET code file that corresponds with your XAML file. Because this code isn’t necessary, you can simply delete this file. The next step is to create your editor class. Create a new class called MaxIntegerEditor in your Design project and add the code that’s shown in Listing 20-9.

669

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-9.  Creating a custom property editor

670

Chapter 20 ■ Creating Data and Presentation Extensions

671

Chapter 20 ■ Creating Data and Presentation Extensions

672

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-9 defines the factory class that specifies the PropertyValueEditorName attribute . The value of this attribute identifies your custom editor control, and this is the value that you specify in your business type’s LSML file to link an attribute to a custom editor. When the LightSwitch table designer needs to display a custom editor, it uses the factory class to create an instance of a MaxIntegerEditor object . The table designer calls the GetEditorTemplate  method to retrieve the UI control to display on the property sheet. This UI control binds to an ICommand object, and the UI control can access this object through the EditorContext property. This UI control shows a hyperlink on the properties sheet, and when the developer clicks the on the link, it calls the code in the Execute method , which opens the dialog. This allows the developer to set the MaxDays attribute, and once the developer enters the value, the code sets the underlying property value using the value that was supplied through the dialog. The next step is to link your custom editor class to your custom attribute. To do this, open the LSML file for your business type, find the section that defines the UIEditor, and modify it as shown in Listing 20-10.

673

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-10.  Creating a custom property editor

Listing 20-10 shows the snippet of XML that links the custom editor to the MaxDays attribute. The important thing to note here is to make sure that the UIEditor value  matches the PropertyValueEditorName value that you set in Listing 20-9.

Using Your Business Type The duration business type is now complete, and you’re ready to build and use it. To demonstrate how to use the business type that you created, open the Timesheet table and select the DurationMins property. In the table designer, you can change the data type from Integer to Duration, and when you open the properties sheet, you can click the Maximum Days link to open the dialog that contains the slider control (Figure 20-5).

Figure 20-5.  The new slider control that appears in the properties sheet Figure 20-6 shows a screen at runtime. The Maximum Days setting for the DurationMins property is set to two days, and the screenshot shows the error message that appears when you try to enter a duration that’s greater than two days. Notice how the control type for DurationMins is set to a textbox rather than the default duration editor control. This emphasizes that LightSwitch applies your business-type validation, irrespective of the control type that you choose.

674

Chapter 20 ■ Creating Data and Presentation Extensions

Figure 20-6.  Business-type validation at runtime

Creating a Custom Shell Extension By creating a LightSwitch shell, you can radically change the appearance of your application. A custom shell allows you to change the position of where the command menu, navigation items, and screens appear. When you add a new shell, the template creates a blank canvas that allows you to add as little or as much as you like. If, for some reason, you don’t want to include a navigation menu, that’s no problem—you can simply choose not to implement that functionality. Some developers have created bare shells and used custom controls to achieve an appearance that looks nothing like a LightSwitch application. Custom shells, therefore, allow you to carry out extreme modification to your application’s UI. A custom shell is a Silverlight concept, so the work that you’ll carry out takes place in your Client project. A LightSwitch shell consists of a XAML file that defines the layout and UI elements of your shell. Data binding then allows you to connect your UI elements with your LightSwitch application through special view models that LightSwitch provides. In this section, I’ll show you how to build a custom shell. To demonstrate how to modify the behavior of your shell, I’ll show you how to create a navigation system that uses drop-down boxes. The overview of how to create a custom shell involves the following: 1. Create a new shell and set the name and description. 2. Write the XAML that defines your shell’s UI and data binds to LightSwitch’s view models. 3. Write the underlying .NET code that supports your shell.

Preparing Your Project Just as you would with all extension types, you would create a new shell by right-clicking your LSPKG project, choosing the “Add ➤ New” option, and selecting “Shell” in the Add New Item dialog. To carry out the example that’s shown in this section, create a new shell called ApressShell. Once you do this, the template creates the following two files: •

Client\Presentation\Shells\ApressShell.xaml This file contains the markup that defines the presentation and UI elements for your shell.



Client\Presentation\Shells\Components\ApressShell.vb This .NET code file contains the implementation code that allows your shell to work with MEF (Managed Extensibility Framework), and includes properties that identify your shell.

675

Chapter 20 ■ Creating Data and Presentation Extensions

A large part of the shell development process involves rewriting parts of LightSwitch that you probably take for granted. A new shell provides you with a UI that’s completely blank, and in this section I’ll show you how to recreate the tab controls that allow users to switch screens. This functionality relies on a couple of DLLs that you need to add to your Client project. These DLLs and their default location on a 64-bit computer are shown here: •

System.Windows.Controls.dll C:\Program Files (x86)\Microsoft SDKs\Silverlight\v5.0\Libraries\



Microsoft.LightSwitch.ExportProvider.dll C:\Program Files (x86)\ Microsoft SDKs\LightSwitch\v5.0\Client\

Defining the Look of Your Shell The key part of shell design is to work out how you want your shell to look. The shell that we’ll build in this example stacks the UI elements from top to bottom. Figure 20-7 shows the proposed layout of this shell.

Figure 20-7.  The proposed layout for your shell

676

Chapter 20 ■ Creating Data and Presentation Extensions

The code in Listing 20-11 contains the XAML that achieves the look that’s shown in Figure 20-7. Take a look at this code, but don’t add it to your ApressShell.xaml file yet. It won’t compile because it depends on some components that you haven’t yet defined. Listing 20-11.  Shell UI code

677

Chapter 20 ■ Creating Data and Presentation Extensions

678

Chapter 20 ■ Creating Data and Presentation Extensions

You can use the comments in Listing 20-11 to match the code blocks with the screen sections that are shown in Figure 20-7. The first part of this code  defines several supporting resources. This includes the value converters to support the shell’s functionality and a template that defines the tab headings that appear above each screen. The tab heading includes the screen name and elements to indicate whether the screen is dirty or contains validation errors. The next part of the XAML  defines the parent StackPanel that arranges the contents of your shell in a top-to-bottom manner. The first control inside the StackPanel displays the application logo , and the next control is a listbox control  that binds to the screen commands in your application. The standard commands that LightSwitch shows on each screen include “Save” and “Refresh.” The next section contains a pair of combo box controls  that you’ll customize to allow users to navigate your application. The final part of the XAML contains the tab control  that contains the screen area and a TextBlock  that displays the currently logged-in user. In the sections of this chapter that follow, I’ll refer back to this XAML and describe the code that’s shown in further detail. When you add this XAML to your project, make sure to set the two namespace references that are indicated in the name of your project .

679

Chapter 20 ■ Creating Data and Presentation Extensions

Binding Data to Your Shell LightSwitch exposes shell-related data through six view models, which are shown in Table 20-1. Table 20-1.  Shell View Models

Name

View Model ID

Description

Navigation

NavigationViewModel

Provides access to navigation groups and screens

Commands

CommandsViewModel

Provides access to the commands that are normally shown in the command section

Active Screens

ActiveScreensViewModel

Provides access to the active screens in your application (that is, the screens that your user has opened)

Current User

CurrentUserViewModel

Provides information about the current logged-on user

Logo

LogoViewModel

Provides access to the image that’s specified in the application’s logo property

Screen Validation

ValidationViewModel

Provides access to the validation information

LightSwitch provides a Component View Model Service that allows you to bind UI elements to view models by simply adding one line of code against the control that you want to data bind. The Component View Model Service uses MEF to find and instantiate a view model and to set it as the data context for the specified control. The advantage is that it makes it really simple for you to consume the data from the view models. To demonstrate how this works, let’s take a closer look at the XAML that shows the screen commands (Listing 20-12). Listing 20-12.  Command bar section

680

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-12 is a simplified version of the code from Listing 20-11 that highlights the parts that are specific to data binding. The first section of this code defines a listbox control. If you’re not familiar with Silverlight, it’s useful to understand that this control isn’t only just designed to display simple lists of text data. It allows you to bind to a data source and to render each data item using rich data controls that can include images and other Silverlight controls. The initial part of listbox control defines the “parent” container for your list items. This code renders the child items horizontally by defining an ItemsPanelTemplate element that contains a StackPanel with its Orientation set to Horizontal . The definition of the listbox control uses the Component View Model Service to bind it to the commands view model. It does this by applying the following line of code:

The Component View Model Service requires you to supply a view model name. The name that you provide should begin with Default, followed by the view model ID that’s shown in Table 20-1. The code that’s shown in  sets the data context of your listbox to the commands view model. The commands view model exposes the individual commands through a collection called ShellCommands, and the next line of code data binds the ItemsSource of the listbox control to this collection . The DataTemplate section presents each data item in your listbox as a button. Each button is bound to an IShellCommand object, and you can use the properties of this object to control the enabled status , image , and display name  of each command item. When a user clicks on one of these buttons, LightSwitch won’t automatically execute the command. You’ll need to write custom code that executes the command, which you’ll find out how to do shortly.

Displaying Your Application’s Logo The top section of your shell displays the logo that’s defined in the properties of the LightSwitch application. You can show the application logo by using the Component View Model Service to bind an image control to the logo view model. Listing 20-13.  Displaying a logo

Listing 20-13 illustrates the code that you would use and provides another example of how to use the Component View Model Service.

Adding Code That Supports Our Custom Shell Up till now, I’ve shown you plenty of XAML that defines the appearance of your shell. Although the big advantage of custom shells is that they allow you to carry out extreme UI customization, the side effect is that you need to implement a lot of the functionality that you would take for granted in LightSwitch. This includes writing the code that executes command items, manages screens, and enables navigation. To support the XAML that you’ve created so far, you’ll need to add the following code to your shell: •

ApressShell.xaml.vb or ApressShell.xaml.cs This defines the .NET code behind your XAML file and contains the logic that enables your custom shell to open and close screens and respond to user-initiated actions.

681

Chapter 20 ■ Creating Data and Presentation Extensions



ScreenWrapper class LightSwitch’s screen object doesn’t contain any properties that allow you to determine whether a screen is dirty or contains validation errors. This object extends LightSwitch’s IScreenObject and provides these extra functions.



Value Converters The shell that you’ve created includes UI elements that indicate whether the screen is dirty or contains validation errors. These value converters help to convert the property results from your screen object into types that your UI controls can consume.

Let’s begin by creating your ScreenWrapper class. Add a new class in your Client project’s Presentation > Shells folder and call it ScreenWrapper. Now, add the code that’s shown in Listing 20-14. Listing 20-14.  ScreenWrapper object

682

Chapter 20 ■ Creating Data and Presentation Extensions

683

Chapter 20 ■ Creating Data and Presentation Extensions

684

Chapter 20 ■ Creating Data and Presentation Extensions

685

Chapter 20 ■ Creating Data and Presentation Extensions

686

Chapter 20 ■ Creating Data and Presentation Extensions

687

Chapter 20 ■ Creating Data and Presentation Extensions

When you create a custom shell, it’s important to be able to access screens in code, and the ScreenWrapper object allows you to do this. It provides a thin wrapper around the IScreenObject object and exposes properties you use to determine if a screen is dirty or contains validation errors. The code in Listing 20-14 includes the following features:

688



1 - Change Notification This class implements the INotifiedPropertyChanged interface and the PropertyChanged event. This allows the ScreenWrapper object to raise a notification if the underlying data becomes dirty or invalid. Ultimately, this allows you to build a UI that shows an indication as soon as a user makes a change or enters invalid data.



2 - Exposes an IsDirty Property This class allows you to determine whether the user has made any data changes by providing an IsDirty property. This returns true if the screen contains changes.



3 - Exposes a ValidationResults Property This class exposes a public property called ValidationResults that allows you to access any underlying validation errors.



4 - Implements Underlying Screen Properties The class implements the underlying properties of IScreenObject and allows you to access the screen’s name, display name, and description in code. It also exposes methods such as Save and Refresh, which allow you to call these methods in code.

Chapter 20 ■ Creating Data and Presentation Extensions

Once you add the ScreenWrapper class, the next step is to create the helper class that contains the value converters. To do this, add a new class in your Client project’s Presentation > Shells folder and call it ShellHelper. Now, modify your code, as shown in Listing 20-15. Listing 20-15  ShellHelper (value converter) code

689

Chapter 20 ■ Creating Data and Presentation Extensions

690

Chapter 20 ■ Creating Data and Presentation Extensions

691

Chapter 20 ■ Creating Data and Presentation Extensions

This code defines four value converters; you’ll notice references to these converters in the XAML code that’s shown in Listing 20-11. The following list describes how these value converters apply to the XAML:

692



WorkspaceDirtyConverter The template for the screen tab title includes a text block that shows the value “*”; this symbol indicates to the user that the screen is dirty. The Visibility property of this text block is data-bound to the ScreenWrapper object’s IsDirty property. The WorkspaceDirtyConverter converts the Boolean IsDirty property to the visibility values of either Visible or Collapsed. Setting the visibility of a Silverlight control to Collapsed hides the control completely. The other visibility value that you can you set is Hidden. The difference between Hidden and Collapsed is that Hidden hides the control, but displays white space in its place instead.



ScreenHasErrorsConverter The screen tab title includes a text block that shows the value “!”; this symbol indicates to the user that the screen contains validation errors. The Visibility property of this text block is data-bound to the ScreenWrapper object’s ValidationResults.HasErrors property. The ScreenHasErrorsConverter converts the Boolean result to a visibility value of either Visible or Collapsed.



ScreenResultsConverter The tooltip property of the screen tab is bound to the ScreenWrapper’s ValidationResults property. This allows the user to hover his or her mouse over a screen tab to see a summary of any validation errors. ValidationResults returns a collection of errors, and the purpose of ScreenResultsConverter is to combine the individual error messages into a single string.

Chapter 20 ■ Creating Data and Presentation Extensions



CurrentUserConverter The text block in the bottom part of the shell displays the name of the currently logged-on user. The data context of this control is the CurrentUserViewModel, and the text block binds to the CurrentUserDisplayName property. If authentication isn’t enabled in the LightSwitch application, CurrentUserConverter returns a string that indicates this condition, which is friendlier than showing nothing at all.

Now, compile your project so that the value converter code becomes available. You can now add the XAML for your shell, which was shown in Listing 20-11, and you can also add the .NET code-behind that’s shown in Listing 20-16. Listing 20-16.  XAML code-behind logic

693

Chapter 20 ■ Creating Data and Presentation Extensions

694

Chapter 20 ■ Creating Data and Presentation Extensions

695

Chapter 20 ■ Creating Data and Presentation Extensions

696

Chapter 20 ■ Creating Data and Presentation Extensions

697

Chapter 20 ■ Creating Data and Presentation Extensions

698

Chapter 20 ■ Creating Data and Presentation Extensions

699

Chapter 20 ■ Creating Data and Presentation Extensions

Although Listing 20-16 contains a lot of code, you can split the logic into three distinct sections: •

Section 1 – screen-handling code



Section 2 – command button-handling code



Section 3 – screen-navigation code

In the sections that follow, I’ll explain this code in more detail.

Managing Screens The LightSwitch API provides an object called INavigationScreen. This object represents a screennavigation item and provides a method that you can call to open the screen that it represents. The navigation view model gives you access to a collection of INavigationScreen objects, and, in general, you would bind this collection to a control that allows the user to select a screen. INavigationScreen provides an executable object that you can call to open a screen. But when you call this method, LightSwitch doesn’t show the screen to the user. The runtime simply “marks” the screen as open, and you’ll need to carry out the work that shows the screen UI to the user. To work with screens, you’ll need to use an object that implements the IServiceProxy interface. This allows you to set up notifications that alert you whenever the runtime opens a screen, and you can use these notifications to add the code that shows the screen UI to the user. In Listing 20-16, the

700

Chapter 20 ■ Creating Data and Presentation Extensions

shell’s constructor uses the IServiceProxy to subscribe to the ScreenOpened, ScreenClosed, and ScreenRefreshed notifications. The code that you’ll find in “Section 1 – Screen-Handling Code” defines the following methods: •

OnScreenOpened: Your shell calls this method when the runtime opens a screen. It creates a tab item and sets the contents of the tab to the UI of the newly opened screen. Screen objects expose their UI contents via a property called RootUI. The code creates a ScreenWrapper object from the underlying IScreenObject object and sets the data context of the tab item to the ScreenWrapper object.



OnScreenClosed: This method executes when the runtime closes a screen and removes it from the application’s collection of active screens. This custom method removes the tab item that displayed this screen, sets the selected tab to be the last tab in the tab control, and sets the current screen to the screen that’s contained in that tab.



OnScreenRefreshed: When a user refreshes a screen, the runtime actually creates a new IScreenObject and discards the old one. This screen replaces the data context of the tab item that contains the screen with a ScreenWrapper object that represents the new IScreenObject instance.



OnTabItemSelectionChanged: This method handles the SelectionChanged event of the tab control. The XAML for the tab control (Listing 20-11) defines OnTabItemSelectionChanged as the method that handles the SelectionChanged event. When a user switches tabs, this code uses the proxy to set the active screen. It’s important that you do this, because it causes the commands view model to update itself to reflect the commands of the new screen.

Executing Commands The custom shell includes a command bar section that renders your screen commands using buttons. Typically, every screen includes save and refresh commands, in addition to any other commands that the developer might add through the screen designer. Technically, the shell implements the command bar section through a list control that data binds to the commands view model (Listing 20-11). The list control’s data template defines a button control that represents each command data item. The data context of each button control is an object that implements the IShellCommand interface. The IShellCommand object exposes a member called ExecutableObject. This object represents the logic that’s associated with the command item. So, to make the buttons on your command bar work, you need to handle the Click event of the button, retrieve the IShellCommand object that’s bound to the button, and call the IShellCommand object’s ExecutableObject’s ExecuteAsync method. This code is shown in the GeneralCommandHandler method, in Listing 20-16 (Section 2 — Command Button-Handling Code).

701

Chapter 20 ■ Creating Data and Presentation Extensions

Performing Navigation Your custom shell includes a pair of combo boxes that allow your users to navigate your application. The first combo box displays a list of navigation groups. When the user selects a navigation group, the second combo box populates itself with a list of screens that belong to the selected navigation group. The first navigation group combo box binds to the navigation view model’s NavigationItems collection. When a user selects a navigation group using the first combo box, the shell runs the code in the navigationGroup_SelectionChanged method and sets the data source of the second combo box to the Children collection of the NavigationGroup. This binds the second combo box to a collection of INavigationScreen objects. When the user selects an item from the second combo box, the shell executes the navigationItems_ SelectionChanged method. The code in this method retrieves the INavigationScreen object that’s bound to the selected item in the combo box. Just like the IShellCommand object, the INavigationScreen object exposes an ExecutableObject. The code then calls the ExecutableObject.ExecuteAsync method. This causes the runtime to open the screen and triggers the code that’s defined in your OnScreenOpened method. The code in this method creates a new screen tab and carries out the remaining actions that are needed to show the screen UI to the user. Figure 20-8 illustrates this process.

Figure 20-8.  Custom navigation process

Persisting User Settings The IServiceProxy object includes a user-settings service that allows you to persist user settings, such as the positions of screen elements. For example, if you create a shell with a splitter control that allows users to apportion the visible screen area between the navigation and screen areas, you can save the screen sizing details when the user closes your application and restore the settings when your user next opens your application. To demonstrate the user-settings service, we’ll add a feature to the shell that allows the user to hide the “logged-in user” section if authentication isn’t enabled in the application. When the user closes an application that doesn’t have authentication enabled, you’ll display a confirmation dialog that allows the user to permanently hide the “logged-in user” section. Listing 20-17 shows the code that adds this feature.

702

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-17.  Saving user preferences

703

Chapter 20 ■ Creating Data and Presentation Extensions

The code in the constructor adds an event handler for the user-settings service’s Closing event . LightSwitch raises this event when the user closes your application. The user-settings service exposes two methods: GetSetting and SetSetting. The SetSetting method allows you to persist a setting by supplying a name/value pair as shown in . When your application loads, the code in the constructor hides the LoggedInUser text block if the value of the HideLoggedInUser setting is true .

Setting the Name and Description The name and description for your shell are defined in the LSML file for your shell. Developers can view these details through the properties window of their LightSwitch solution. To set these details, modify the DisplayName and Description attributes, as shown in Listing 20-18.

704

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-18.  Setting the name and description

Using Your Custom Shell Your custom shell is now complete, and you can now build and share it with other developers. Once a developer installs your extension, LightSwitch adds your custom shell to the list of available shells that it shows in the properties window of each application. A developer can apply your shell by selecting it from the list. Figure 20-9 shows the final appearance of your screen.

Figure 20-9.  Illustration of the final shell

705

Chapter 20 ■ Creating Data and Presentation Extensions

Creating a Custom Theme Extension Custom themes are the ideal companion to a custom shell. You can use themes to customize your application’s font, color, and control styles. You’ll be pleased to know that it’s much simpler to create a theme than it is to create some of the extension types that you’ve already worked on. The process involves the following steps: 1. Creating a new theme and setting the name and description. 2. Modifying the style information that’s defined in the theme’s XAML file. To begin, right-click your LSPKG project, select “New Item,” and create a new theme called ApressTheme. As soon as you do this, the template creates an XAML file in your Client project and opens it in Visual Studio’s XML text editor. The template prepopulates this file with default fonts and colors. It groups the style definitions into well-commented sections. At this point, you could build and deploy your theme. But before you do this, let’s modify the fonts and colors that your theme applies.

Applying a Different Font The default theme that the template creates uses the Segoe UI font, and you’ll find references to this font throughout your theme file. Figure 20-10 shows a screenshot of the theme file in Visual Studio’s editor. Notice how the file defines font styles, and notice how it sets the FontFamily value to Segoe UI, Arial. This setting defines Segoe UI as the preferred font and Arial as the fallback font. This means that LightSwitch will apply the Arial font only if the Segoe UI font isn’t available on the end-user PC.

Figure 20-10.  The contents of your theme file in Visual Studio

706

Chapter 20 ■ Creating Data and Presentation Extensions

To change the font, simply replace the references to “Segoe UI” with the name of the font that you want to use. For example, you could replace “Segoe UI” with “Times New Roman,” “Tahoma,” or “Verdana.” To perform a global change, you can use Visual Studio’s “Find and Replace” option. You can find a full list of font name values that you can use through the following page on MSDN: http://msdn.microsoft.com/en-us/library/cc189010(v=vs.95).aspx

Setting Different Colors Changing the colors in a style is just as easy. For example, refer back to the command bar control that you added in the custom shell section. Listing 20-19 shows the code that defines the listbox control that contains the command buttons. You’ll notice that this code applies the static resource RibbonBackgroundBrush to the listbox control’s Background property. RibbonBackgroundBrush defines a key that links a shell with a theme. Listing 20-19.  CommandPanel section of shell

If you now use the find feature in Visual Studio to search for the string RibbonBackgroundBrush in your theme file, you’ll find an entry that relates to this style. To apply a different background style, you can modify this entry as appropriate. To demonstrate this, we’ll apply a diagonal gradient background style that goes from white to black. Modify the RibbonBackgroundBrush style in your theme as shown in Listing 20-20. Listing 20-20.  Setting the theme colors

707

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-20 defines the color codes that allow you to replicate this example. But rather than manually hand-code the styles in your theme, you can select a style entry and use the graphical designer that you’ll find in the properties sheet to define your colors and gradient styles (Figure 20-11).

Figure 20-11.  The contents of your theme file in Visual Studio To complete your theme, the final step is to specify a name and description. The LSML file for your theme allows you to define these settings. You’ll find this file in your Common project, in the following location: ...Common\Metadata\Themes\ApressTheme.lsml Once you build and install your theme extension, you can apply it to your LightSwitch application through the properties windows for your application. Figure 20-12 shows the command bar section of an application that applies the ApressTheme and highlights the white-to-black gradient style that runs from the top left to bottom right.

Figure 20-12.  Applying a gradient background to the command bar

Creating a Screen Template Extension If you frequently create screens with common patterns, features, and code snippets, you can save yourself time by creating a custom screen template. In this section, I’ll show you how to build screen extensions for desktop and HTML client applications. To explain this technique, I’ll demonstrate how to incorporate two of the screen designs from this book into screen template extensions. For the desktop client applications, I’ll create a template that builds a combined Add/Edit screen. And for HTML client applications, I’ll show you how to create a template that builds a View screen that features a Delete button and confirmation popup.

708

Chapter 20 ■ Creating Data and Presentation Extensions

The manual process to build both of these screens involves several detailed steps. Therefore, the benefit of a screen template is that it automates these repetitive tasks and can save you time in the long run. The steps to build desktop and HTML screen templates are very similar. To begin, I’ll demonstrate the desktop client screen template, which involves the following steps: 1. Add a screen template item and specify the template properties. 2. Write code that generates the templated screen controls. 3. Write code that generates the templated .NET code. To add a new screen template item to an extension solution, right-click your LSPKG project, select “New Item,” and choose the “Screen Template” option. For this example, name your screen template AddEditScreenTemplate. Once you add a new screen template, Visual Studio opens the code file for your template in the code editor.

Setting Template Properties You can set the properties of your template by changing the code that appears in the first section of the screen template’s code file. These properties include the name, description, and display name of your template. The screen template exposes many of these properties through Visual Studio’s Add New Screen dialog. Figure 20-13 illustrates this dialog and highlights the places where the Add New Screen dialog applies the screen template properties.

Figure 20-13.  Add New Screen dialog

709

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-21 highlights the places in the code file where you can set these properties. Listing 20-21.  Creating a screen template extension

710

Chapter 20 ■ Creating Data and Presentation Extensions

The DisplayName property  defines the text that appears on the left-hand side of the Add New Screen dialog. When a developer selects a screen template, the dialog uses the value of the Description property  to set the text that appears in the center of the dialog. It also sets the value of the Screen Text textbox by using the StringNameFormat property . In this example, the StringNameFormat property value includes a substitution character. This enables the Add New Screen dialog to prepend the data-source name to the beginning of the text that it shows in the Screen Text textbox. The value of the SupportsChildCollections property  controls the visibility of the “Additional Data to Include” checkboxes. The RootDataSourceType  property defines the content that appears in the screen data drop-down. I’ll describe this in greater detail in the next section. In addition to these properties, there are two additional properties you can use to set the image and icon of your screen template.

711

Chapter 20 ■ Creating Data and Presentation Extensions

Defining the Data-Source Type When a developer selects a screen template from the Add New Screen dialog, the dialog populates the screen data drop-down with data that depends on the selected template. When you build a screen template, you can define the data that appears in the screen data drop-down by setting the RootDataSource property. Table 20-2 shows the four values that you can set for this property. Table 20-2.  Query Types

Name

Description

Collection

Allows the developer to select collections or multiple result queries

ScalarEntity

Allows the developer to select a single entity type or queries that return one item

NewEntity

Used for screens that are intended to create new entities

None

Used for screens in which no data needs to be selected

In our example template, set the RootDataSource property to ScalarEntity. This configures the screen data drop-down to show singleton queries when a developer selects your screen template.

Generating Screen Controls The first and most important part of screen template design is to work out the screen components that you want to include in your template. The best way to do this is to create a normal screen and to use that to establish your requirements. Figure 20-14 shows the Add/Edit screen from Chapter 9 and highlights the steps to build this screen in the designer.

Figure 20-14.  Screen requirements Once you establish the items that you want to add to your template, you need to translate these tasks into code. The screen template produces screens by calling a method called Generate. Listing 20-22 shows the code that produces the screen that’s shown in Figure 20-14.

712

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-22.  Creating a desktop client screen template extension

713

Chapter 20 ■ Creating Data and Presentation Extensions

714

Chapter 20 ■ Creating Data and Presentation Extensions

The list below highlights the actions you would carry out in the screen designer if you were to create the screen manually, and it identifies the corresponding code in Listing 20-22 that carries out the same task. •

Creating a Details screen and query The Add/Edit screen is based on a query that returns a single record by ID value. The good news is that you don’t need to write any specific code to create the screen’s underlying query. The screen template automatically creates a query when you set the RootDataSource to ScalarEntity. You can use the syntax host. PrimaryDataSourceProperty  to access the query that LightSwitch generates. If you set the RootDataSource to NewEntity instead, the PrimaryDataSourceProperty object would be a property that matches the data type the developer chooses in the Add New Screen dialog. And if you set the RootDataSource to Collection, the PrimaryDataSource would be a collection of entities (that is, a visual collection).



Adding group layouts Let’s imagine that you select a node in the screen designer's tree view and click the “Add” drop-down button. The code equivalent that performs this action is the AddContentItem method. This method requires you to supply the content item type that you want to add along with the name you want to give your new data item. The code in Listing 20-22 adds a new group layout by specifying the content item kind of ContentItemKind.Group .



Adding a local property that matches the underlying query’s data type To add a new local property in the screen designer, you open the Add Data Item dialog and choose the radio option to add a local property. To carry out the same action in code, you would call the AddScreenProperty method . Just like the Add Data Item dialog, you need to supply the name and data type of your new property. The code uses the PrimaryDataSourceProperty object to determine the data type of the underlying screen object and names the property after the entity type name, but with the word “Property” appended to the end. Another useful method is the AddScreenMethod method. This is the code equivalent of creating a screen method through the Add Data Item button.



Making the query parameter optional To enable your screen to work in New Data entry mode, you must set the ID parameter on your screen to be optional. You might expect to find a Boolean property you can use to set the optional status of a parameter to false, but interestingly, no such property exists. So, to make a parameter optional, you need to carry out a step that may seem unusual. To make a parameter optional, you simply change the underlying data type from an integer to a nullable integer, as shown in .



Deleting the screen properties that are bound to the query When you create an Add/Edit screen manually through the screen designer, you need to delete the data items that bind to the underlying query. You don’t need to carry out this action when you create a screen template in code. The screen that the screen generator creates includes only the root element and doesn’t include any extra content that you would need to delete.

715

Chapter 20 ■ Creating Data and Presentation Extensions



Adding screen properties that bind to your local entity property When you create an Add/Edit screen manually through the screen designer, the final step is to drag your local property onto your screen and to add data items that bind to your local property’s data items. The AddContentItem method  allows you to add the local property onto your screen in code. If you carried out this task in the screen designer, LightSwitch would render your local property as an auto-complete box. In code, the AddContentItem method does the same thing—it’ll add the local screen property as an auto-complete box. To change the auto-complete box to a rows layout in code, you would call the SetContentItemView method. This method accepts a reference to the content item and a ViewID that identifies a rows layout .

A common design task is to set the control type for a data item, and, therefore, the SetContentItemView method is a very useful method. However, the difficulty with this method is that you set the control type with a ViewID and it’s not obvious what ViewID you need to use. To help you, I’ve included a list of ViewIDs you can use in Appendix C. Another useful method you can call is the ExpandContentItem method. This method expands a content item by adding child items that represent each property in the entity. This method mimics the use of the Reset button in the LightSwitch screen designer.

Generating Screen Code Any screen that you want to generate from a template will most likely require some sort of custom code, and the Add/Edit screen is no exception. This screen requires code in its loaded method to create a new instance of your local screen property and to set the value of the local screen property to the results of the underlying screen query. The final part of Listing 20-22 creates the screen’s .NET code by calling the AddScreenCodeBehind method. A developer can use your screen template from either a VB or C# application. The host. ScreenCodeBehindLanguage property returns the language of the target application, and you can use this information to build your screen's source code in the correct language. The code retrieves a languagespecific template from a dictionary called _codeTemplates. It then uses .NET’s String.Format method to substitute the required values into the template (Listing 20-23). The purpose of this code is to recreate the code from the Add/Edit screen sample from Chapter 9.

716

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-23.  Creating screen template code

717

Chapter 20 ■ Creating Data and Presentation Extensions

Another way to generate code is to use .NET’s Code Document Object Model (CodeDOM). CodeDOM is specially designed for this purpose, and you can read more about it on the following Microsoft web page: http://msdn.microsoft.com/enus/library/650ax5cx.aspx. However, this example uses string substitution because it’s simple to understand and saves you the small task of having to learn a new API.

718

Chapter 20 ■ Creating Data and Presentation Extensions

Creating More Complex Screen Templates Your Add/Edit screen template is now complete, and you can now build and deploy your extension. The template-generation host allows you to do much more than this chapter shows; for example, you can add query parameters, related collections, and entity properties to your screen. You can use Visual Studio’s IntelliSense to work out the purpose of the host generation methods, so designing more complex screens shouldn’t be difficult. If you want to create more complex screen templates, my best advice is to create your screen as normal in your LightSwitch application. You can then examine the LSML markup for your screen to help figure out the objects that you need to build in code. This technique comes in handy when you want to work out the correct ViewIDs to use (especially when you use custom controls) and when you want to build ChainExpressions that enable you to access the selected item in a collection. I’ll demonstrate this technique in the next section, where I will show you how to build an HTML screen template extension.

Creating an HTML Screen Template Extension In this section, I’ll show you how to build an HTML screen template extension. The steps to build one are almost identical to those that you use to build a desktop screen template extension. I’ll show you how to create a template to build a screen that displays a single record. The output screen will include a button that the user can click to delete the record. Before the screen carries out the deletion, it will prompt the user to reconfirm the action with a popup dialog. This screen is identical to the one I showed you in Chapter 8, and you can refer to that chapter to find out more. Just like the desktop client example, the key to screen template design is to build a screen with the designer in a LightSwitch application. You can use this process to itemize the tasks that you need to carry out. Figure 20-15 illustrates a list of steps that are required to build this screen.

Figure 20-15.  HTML client screen template steps

719

Chapter 20 ■ Creating Data and Presentation Extensions

To build a template for this screen, add a new screen template item by selecting the right-click menu item on the LSPKG project. Name your screen template ViewDeleteScreenTemplate. Once you add your template, you must designate it as an HTML client screen template rather than a desktop client screen template. To do this, open the code file for your template and locate the factory class definition. Now, decorate the class with the TargetPlatform attribute value and set the value to MobileWeb, as shown in Listing 20-24 . For the code to recognize this attribute, use the Imports/Using statement to add a reference to the Microsoft.LightSwitch.DesignTime namespace at the top of your code file. Listing 20-24.  Designating a screen template as an HTML client screen template

720

Chapter 20 ■ Creating Data and Presentation Extensions

The next step is to set the properties of your screen template, such as the template name and display name. For this example, set the RootDataSource property value to ScalarEntity. This will configure the screen data drop-down to show singleton queries when a developer chooses your screen template. To define the code that generates the screen, add the code from Listing 20-25 to the Generate method. To help you follow this code, you can use the comments to associate the blocks of code with the steps that are shown in Figure 20-15. Listing 20-25.  Creating an HTML client screen template extension

721

Chapter 20 ■ Creating Data and Presentation Extensions

722

Chapter 20 ■ Creating Data and Presentation Extensions

This code shares many similarities with the code that I showed you in the desktop client example. Here’s an explanation of the more notable parts. The initial part of this code adds a tab to the screen. To accomplish this, the code calls the AddContentItem method to add a new group to the main tab control content item. The AddContentItem method requires you to supply a parent content item. You can use the host.ScreenTabPagesContentItem member to refer to the tab control item on the screen . To add data items for the property, add a rows layout and data bind it to the data source of the screen. You can then generate child data items by calling the ExpandContentItem method . You can add a popup with code that looks much the same as the code you use to add a tab control. To add a popup, call the AddContentItem method to add a new group. When you call this method, use the host.ScreenDialogPagesContentItem member to define the screen’s popup folder as the parent content item . The next section of code that warrants further explanation is the part that adds a button to the popup control . To achieve this, the code adds a screen method called DoDelete. The next block of code defines a content item of type Command (this is a content item object that represents a button). The remaining code then associates this content item with the DoDelete method. Note that for brevity I omitted the code that defines the popup’s Cancel button. You can easily add this button by applying the same coding technique. The next section of code creates the button that opens the popup . The syntax looks very similar to the code that adds the Delete button. A significant difference is that the code that defines the popup button sets the icon of the button to an image of a trash can. The code you use to assign an icon isn’t obvious. As I mentioned earlier, the trick to working out what code to use is to examine the LSML on an existing screen. To illustrate this technique, open a LightSwitch project and find a screen that includes a button with a trash can icon. From Solution Explorer, open your screen in the XML editor. To do this, right-click your screen in Solution Explorer and select the “open with” menu item. When the Open With dialog opens, choose the “XML (Text) Editor” item. This opens an XML view of your data, as shown in Figure 20-16.

Figure 20-16.  LSML view of a screen

723

Chapter 20 ■ Creating Data and Presentation Extensions

From the XML data, you can identify the line that defines the trash icon. This view shows that the LSML defines a trash icon with a ConstantExpression that is wrapped inside ChainExpression, ScreenExpressionTree, and ControlPoperertySource elements. So, to assign the trash can image to a button, you can use the .NET API methods to recreate this XML structure in code. As Listing 20-25 shows, you can declare new ConstantExpression and ChainExpression objects in code. You can then call the host.SetControlPropertyExpressionTree method to assign a control property to the content item. The final section of code defines the JavaScript code for the screen . The code uses a string builder object to build the code and then calls the host.AddScreenCodeBehind method to append the JavaScript to the code file of your screen.

Creating a Data-Source Extension In the final part of this chapter, I’ll show you how to create a data-source extension. Data-source extensions allow developers to consume data sources that are not natively supported by LightSwitch. Although there are several other ways to connect to external data, including RIA Services and OData, the benefit of a data-source extension is that you can more easily package and share the code that consumes a data source. In this section, you’ll learn how to create a data-source extension that connects to the Windows event log on the server. The purpose of this example is twofold. The first is that it demonstrates how to connect to a slightly unusual data source, while the second reason is slightly more practical. You can use this data source to display your server’s event log from within your application so that, once you deploy your application, developers or support staff can view the errors that your application generates without needing access rights to log on to the server. Here’s an overview of the steps to create the Windows event log data-source extension: 1. Create a new data-source extension and name it WindowsEventLog. To do this, right-click your LSPKG project, select “New Item,” and choose the “Data Source” option. 2. Add entity classes to represent event sources and event log entries. 3. Add the RIA Services code that retrieves the event log data.

Creating an Entity Class Just as in the RIA services code from Chapter 14, you need to define entity classes to enable LightSwitch to consume your data. To carry out this example, you’ll need to create a pair of entity classes: a class that represents an event log entry and a class that represents an event log source. An event log source represents a group of event log entries. (The Application, System, and Security logs in the Windows event log are examples of sources.) To add these classes, create a new class file in your Server project, name it EventLogEntityClasses, and add the code that’s shown in Listing 20-26.

724

Chapter 20 ■ Creating Data and Presentation Extensions

Listing 20-26.  Entity class for event log

725

Chapter 20 ■ Creating Data and Presentation Extensions

In the code that’s shown in Listing 20-24, notice how the primary-key property is decorated with the key attribute, and how it’s also decorated with the Editable attribute, with the value set to false. LightSwitch uses these attributes to prevent users from editing the ID property and to render it on screens by using read-only controls. You can specify the Required attribute to define a mandatory property. You can also configure the StringLength attribute to specify the maximum length of a property. Both these attributes enable LightSwitch to apply its built-in validation, and they prevent users from saving data that violates the rules that you specify. A highlight of this code is that it defines a relationship between the LogSource and LogEntry entities. A single LogSource record can be associated with many LogEntry entries, and the Association attribute defines this relationship between the two entities.

726

Chapter 20 ■ Creating Data and Presentation Extensions

Creating the Data Service Class The next step is to write the code in your domain service class. Just like the RIA service example, this class contains the logic that adds, updates, retrieves, and deletes the data from your underlying data source. The data-source template creates a domain service class called WindowsEventLog. To implement your domain service class, add the code that’s shown in Listing 20-25. Listing 20-25.  Domain service code for accessing data

727

Chapter 20 ■ Creating Data and Presentation Extensions

728

Chapter 20 ■ Creating Data and Presentation Extensions

729

Chapter 20 ■ Creating Data and Presentation Extensions

730

Chapter 20 ■ Creating Data and Presentation Extensions

731

Chapter 20 ■ Creating Data and Presentation Extensions

This code relies on the methods in the System.Diagnostics namespace to retrieve the event log messages. The code decorates the GetEventEntries method with the Query(IsDefault=true) attribute  . This indicates that LightSwitch should use it as the default method for returning a collection. This code includes logic that limits that number of entries to return to 200, and it also includes an error trap that allows the code to skip over event sources that it can’t access because of insufficient permissions. In practice, you can modify this code so that it better handles these conditions. Because the Windows event log doesn’t allow you to update or delete individual entries, notice that the code doesn’t implement the UpdateLogEntry and DeleteLogEntry methods.

Using the Data-Source Extension You’ve now completed all of the necessary code to build and use a data-source extension. Once you install your extension, you can use it by going to Solution Explorer in your LightSwitch project, selecting the right-click “Add Data Source” option, and choosing “WCF RIA Service.” In the next dialog that appears, you can find an entry for the Windows event log service in the “Available WCF RIA Service classes” listbox, as shown in Figure 20-17.

Figure 20-17.  Using the data-source extension Select the Windows event log service and carry out the remaining steps in the Attach Data Source wizard. Once you complete the steps in the wizard, you can consume the Windows event log in your application, just as you would for any other data source.

732

Chapter 20 ■ Creating Data and Presentation Extensions

Summary In this chapter, you learned how to create business type, shell, theme, and data-source extensions. Business types are special data types that are based on primitive, basic LightSwitch types. When you add a property to a table, you can specify a business type rather than a basic data type like string or integer. Business types provide two distinct benefits. First, they provide bespoke validation, and second, you can associate screen controls with a business type. When you create a new business type, the template creates an LSML file in your project for your business type. You use this file to define the metadata for your business type. The definitions you can specify include the underlying data type, any custom validation that you want to apply, and the attributes that you want to expose through the table designer. To associate your business type with validation code, you specify the name of a validation factory class in your business type’s LSML file. When LightSwitch needs to validate the value of a business type, the factory class returns an instance of a custom validation class that contains your validation logic. The validation code for a business type belongs in the Common project. This is because in the case of a desktop application, the code in the Common project can run on both the server and the client, and this enables LightSwitch to execute the validation in both places. To give an example, LightSwitch’s phone number business type includes an attribute that the developer can use to set a list of valid phone number formats for an instance of the business type. The developer can edit this list by opening a popup dialog from the table designer’s property sheet. In this chapter, I showed you how to add your own custom popup dialogs to Visual Studio’s property sheet. This technique relies on a WPF control that defines your popup editor control. To link this control with an attribute, you specify an attribute in your business type’s LSML file and define a “UI Editor” setting that links the attribute with a factory class. The factory class returns an instance of an editor class that produces the UI that Visual Studio displays in the property sheet. This UI can contain controls that the developer can use to edit your attribute, such as textboxes or checkboxes. But in this case, the UI simply defines a hyperlink that opens the popup dialog. Once the developer edits the value, the editor class updates the underlying attribute through an IPropertyEntry object that the factory class provides. Custom shells enable developers to modify the structure and overall layout of an application. A shell consists of an XAML file that defines the layout of the UI, and also contains controls to manage commands, navigation, and screen interaction. View models allow the UI to consume the application data that LightSwitch exposes. With these view models, you can access navigation items, commands, active screens, and validation details. LightSwitch includes a Component View Model Service that provides easy access to the view models in your XAML code. You can simply add a line of code in your Silverlight control that references the service and supply a view model ID. This sets the data context of your control to the view model, and you can then data bind the properties of your control to the properties that the view model exposes. A custom shell requires you to write the .NET code that executes commands, manages screens, and performs navigation. In this chapter, I showed you how to create a ScreenWrapper object that determines if a screen contains data changes or validation errors. I also showed you how to build custom navigation by implementing a combo box control that enables users to open screens. This control data binds to a collection of INavigationScreen objects through the navigation view model. When a user selects a screen, it triggers code that prompts the LightSwitch runtime to open the selected screen. Although the runtime opens the screen, it doesn’t display any content to the user—this is something that you need to implement yourself. To accomplish this, you can employ a ServiceProxy object to notify you whenever the runtime opens a screen. When this event occurs, you can execute code that displays the screen by adding the content to a tab control. Custom themes enable developers to customize the font, color, and styles that a shell applies. A custom theme defines the styles within an XAML file in your extension project. When you add a new theme, the template creates a working theme that contains well-commented sections that describe each style setting. For example, if you want to change the command-bar style, you can use the comments to find the command-bar section and amend the entries within that section to modify the colors, font names, and font styles.

733

Chapter 20 ■ Creating Data and Presentation Extensions

If you carry out the same repetitive tasks in the screen designer, you can automate the process by creating a custom screen template extension. You define a screen template with .NET code that belongs in the Design project of your extension solution. The code file for your template includes .NET properties you can use to specify the settings of your template. These settings include the name, description, and root data-source type of your template. These settings appear in the Add New Screen dialog when a developer adds a new screen in a LightSwitch application. The root data-source type property is important because it defines the data that fills the “Screen Data” drop-down in the Add New Screen dialog. The .NET method that builds a screen is called Generate. This is the method where you add code to generate your output screen. Inside this method, you can access a screen generator host object to carry out screen-design tasks in code. With this object, you can carry out the same screen-design tasks in code as you would carry out with the screen designer. For example, you can use the host to create local screen properties, add content items, and change the control that renders a data item. The host generator object includes a method you can use to add code to your screen. When you create a desktop screen template, you should write code to build VB and C# versions of your screen code. In the case of HTML client screen templates, you can use the host generator object to add JavaScript code to your output screen. In the final part of this chapter, I showed you how to create a data-source extension. You can build data-source extensions to enable developers to connect to data sources that are not natively supported by LightSwitch. The code in a data-source extension relies on a domain service class, so the code that you use looks very similar to the RIA service code from Chapter 14. In this chapter, I showed you how to create a data-source extension that connects to the Windows event log. To create a data-source extension, you first need to add entity classes that describe the data that your extension returns. You can optionally create associations to define relations between the entity classes in your data source. You can add methods to your domain service class to retrieve, add, update, and delete the data from the underlying data source. Just as if you were writing an RIA service, you must define a default method that returns a collection of data. You achieve this by adding a method that returns data and decorating it with the Query(IsDefault=true) attribute.

734

Part VIII

Securing Your Application

Chapter 21

Authenticating Your Users In the next two chapters, I’ll show you how to secure your LightSwitch application. This chapter covers authentication—the process that determines the identity of your user. Once you identify your user, you can control the screens that they can see and functions that they can perform in your application. I’ll cover this process in the next chapter (Chapter 22), which is on authorization. In this chapter, you’ll learn how to do the following: •

choose an authentication method that suits your application type



apply Windows or Forms authentication in your LightSwitch application



share authentication credentials with other applications

By the end of this chapter, you’ll understand how to enable authentication in your applications. You’ll also have discovered how to force users to enter a username and password at login by enabling Forms authentication.

Choosing an Authentication Method LightSwitch supports two authentication methods: Windows and Forms. When you enable Windows authentication, LightSwitch identifies the logged-in user by using the credentials that they use to log in to their Windows computer. Forms authentication identifies a user by forcing them to enter a username and password when the application starts. Your application type determines the most appropriate type of authentication. Table 21-1 summarizes the options that work best, based on application type. Table 21-1.  Recommended Authentication Methods by Application Type

2-Tier Desktop App Deployed on an Internal Network 3-Tier Desktop or HTML Client App – Deployed on an Internal Network 3-Tier Desktop or HTML Client App – Deployed on the Internet or Azure

None

Windows



 

Forms

 

737

Chapter 21 ■ Authenticating Your Users

The most secure choice for a two-tier desktop application is Windows authentication. In a two-tier application, LightSwitch stores the connection string to your membership database in clear text inside your application’s web.config file, which it stores on the client’s machine. If a malicious user discovers this connection string, they could tamper with your membership data outside of LightSwitch. If you want to make your application available via the Internet (or to deploy to Azure), Windows authentication isn’t really a viable choice. Forms authentication is the best choice in this scenario. In a three-tier local network deployment (with the LightSwitch server components hosted in IIS), you have a choice of either Windows or Forms authentication. Table 21-2 summarizes the features of these two authentication types and explains when to use each type. Table 21-2.  When to Use Each Type of Authentication

Windows

Forms

Use Windows authentication if all of your users belong in the same domain.

Use Forms authentication if you don’t have a Windows domain. This can occur if you install your application on a workgroup or Novell network.

Use Windows authentication if you don’t want Use Forms authentication if you want your users to enter a users to enter a username and password when username and password when they run your application. they start your application You might choose to do this to enforce an extra layer of security. Forms authentication is ideal if you want to share authentication details with other applications, perhaps with an existing ASP.NET website.

No Authentication The Access Control tab in the properties section of your application allows you to manage authentication. By default, LightSwitch disables authentication in all new projects that you create (Figure 21-1).

Figure 21-1.  Default authentication option You would leave authentication disabled if you have no need to know who your users are. This choice is appropriate if you want to provide open access to your application, with no need to control access to certain parts of your application.

738

Chapter 21 ■ Authenticating Your Users

Enabling Windows Authentication To enable Windows authentication, select the “Use Windows authentication” radio button (Figure 21-2). This enables an additional set of radio buttons you can use to choose who can run your application.

Figure 21-2.  Enabling access for specific Windows users The first option requires you to enter each Windows user who can access to your application. You would do this at runtime via the users screen.

Figure 21-3.  Specify users in the users screen at runtime The second option (“Allow any authenticated Windows user”) allows all users who have been authenticated by Windows to run your application. This option is ideal if you want to identify your users, but don’t want to go through the time-consuming process of adding each user to your application. If you enable

739

Chapter 21 ■ Authenticating Your Users

this option, you can still restrict the tasks that individual users can carry out in your application by specifying their login names in the user screen. Chapter 22 will cover this in greater depth. When you deploy your application, you need to designate an application administrator during the publish process. Chapter 23 will describe the publishing process and show you the specific steps that you need to follow.

Forms Authentication When you choose Forms authentication (Figure 21-4), your application will prompt the user for a username and password at start-up. Forms authentication is based on username and password combinations that the application administrator defines.

Figure 21-4.  Enabling Forms authentication There are a couple of security considerations you should to be aware of. First, some IT professionals regard Forms authentication as a less secure option because it stores the usernames and passwords in a database table. For additional security, LightSwitch stores the cryptographic hash of the passwords rather than the clear-text values. Despite this, some administrators may consider this a security risk in environments that need to be very secure. Second, LightSwitch transmits the username and password combination that the user enters at login in clear text across the network. An attacker who snoops the network can discover the usernames and passwords being used. You can help mitigate this risk by enabling HTTPS on your server. The application administrator creates the usernames and passwords at runtime through the users screen, shown in Figure 21-3. The administrator can also use this screen to delete users and to reset passwords. If users want to change their password, they can do so by using an option that LightSwitch provides (Figure 21-5). The location of the control that opens the Change Password dialog depends on the shell that you choose.

740

Chapter 21 ■ Authenticating Your Users

Figure 21-5.  Changing a password

■■Caution  If you enable Forms authentication, you should configure SSL (Secure Sockets Layer) when you deploy your application (see Chapter 23). This encrypts any user login credentials that LightSwitch transmits over the network.

Understanding Where User Details Are Stored When you enable authentication, LightSwitch manages your users with the ASP.NET membership provider, which stores your users in a table called aspnet_Users in the Intrinsic database. Figure 21-6 shows a screenshot of this table. The primary-key field is called UserId and is of data type GUID. The provider stores the usernames in a field called UserName.

Figure 21-6.  aspnet_Users table LightSwitch stores the roles you define in a table called aspnet_Roles. This is shown in Figure 21-7.

Figure 21-7.  aspnet_Roles table

741

Chapter 21 ■ Authenticating Your Users

The user-to-role settings are stored in a table called aspnet_UsersInRoles. The set of tables that the membership provider uses and the relationships between them are shown in Figure 21-8.

Figure 21-8.  Tables used by the membership provider, as well as their relationships It’s useful to understand the tables that the membership provider uses, because it enables you to create and retrieve user accounts outside of LightSwitch. If you’re familiar with SQL Server, you know you can create users by calling the aspnet_Membership_CreateUser and aspnet_Profile_SetProperties stored procedures.

Changing the Password Complexity Rules When you enable Forms authentication, the membership provider enforces a password complexity rule that helps to keep your application secure. By default, passwords must be eight characters in length and contain a non-alphanumeric character. An example of a valid (but not very strong) password is pass@word1. The default rule provides a good level of security, but some users might find it too restrictive, and you might prefer to weaken this rule. Alternatively, you might even want to strengthen the password complexity rule to insist that users create more-complex passwords. After you deploy your application, you can change the password complexity rule by modifying a setting in your web.config file. When you deploy your application in IIS, you’ll find web.config in the root folder of your LightSwitch application. As I mentioned earlier, Forms authentication doesn’t provide sufficient security for two-tier applications—this section therefore focuses on the three-tier IIS setup.

742

Chapter 21 ■ Authenticating Your Users

Once you find your web.config file, open it in a text editor and search for the ASPNetSQLMembershipProvider element. The membership provider controls the password complexity through the minRequiredPasswordLength and minRequiredNonalphanumericCharacters attributes (shown in Figure 21-9). If these two attributes don’t exist, you can simply add them to your file.

Figure 21-9.  Changing the password complexity rules in the web.config file

Changing Password Encryption Settings By default, LightSwitch saves the hashes of the user passwords rather than the clear-text password. The passwordFormat attribute in the AspNetSqlMembershipProvider element of your web.config file controls this behavior (which you can also see in Listing 21-1). There are three choices that you can enter here: •

Hashed



Encrypted



Clear

Hashed is the default value and is the most secure. When you choose this option, LightSwitch uses a one-way hash algorithm and a randomly generated salt value when it stores passwords in the database. When a user enters a username and password at logon, LightSwitch hashes the password that the user enters and compares it to the value in the database.

743

Chapter 21 ■ Authenticating Your Users

It’s impossible for you to retrieve the plain-text password values when you set the passwordFormat to Hashed. If you want to store your user passwords in plain text inside your aspnet_users table, change the passwordFormat setting to clear. This is obviously less secure, because anyone who can access the aspnet_users table can see all of your passwords. Although this is less secure, there are a couple of reasons why you might choose this option, as follows: •

You might want to build some mechanism outside of LightSwitch to remind users of their actual password.



During the initial set up of your application, you might want to pre-load users and known passwords by manually populating the aspnet_users table. Maintaining clear-text passwords simplifies this process, and means that you don’t need to create an additional process to work out the hash or encrypted value.

Sharing Forms Authentication Data with ASP.NET Let’s imagine that you have an existing ASP.NET website that uses Forms authentication. Because your website already contains a set of users, you might want to share these existing credentials with your LightSwitch application. You can set up your LightSwitch application to share Forms authentication details with existing ASP.NET websites by modifying your web.config file. To do this, deploy your LightSwitch application to IIS and open the web.config file in a text editor (see Chapter 23 for more help on deployment). You’ll need to make the following changes to this file: •

Create a new connection string that points to the authentication database that your existing ASP.NET application uses.



Update the membership, role, and profile provider strings to reference the connection string that you just created.



Ensure that you specify the same ApplicationName is specified in the provider strings in both your LightSwitch and ASP.NET applications.



Specify the same machine-key setting for both of your applications.

To create a new connection string that references the authentication database used by your existing ASP.NET application, search for the connectionStrings element. Beneath the _InstrinsicData connection string that LightSwitch creates, add a new connection string that points to your existing authentication database (as highlighted in Figure 21-10). In this example, I’ve named this new connection string _AuthData.

Figure 21-10.  Creating a new connection string in your LightSwitch application’s web.config file

744

Chapter 21 ■ Authenticating Your Users

Now search for the AspNetMembershipProvider, AspNetRoleProvider, and AspNetProfileProvider entries in the web.config file of your LightSwitch application. By default, the connectionStringName setting for each entry is set to _IntrinsicData by default. Change this to _AuthData (as shown in Figure 21-11).

Figure 21-11.  Modify the connection string and application name settings Open the web.config file for your existing ASP.NET application and search for the AspNetMembershipProvider entry. Find the applicationName that this uses. In this example, let’s assume that the applicationName value is set to ExistingASPApp. Return to the web.config file for your LightSwitch application and set the applicationName of the three provider strings to ExistingASPApp. You need to define the same machine key in both of your applications. Because LightSwitch hashes (or encrypts) passwords, identical machine keys allow both applications to encrypt and decrypt passwords in the same exact way. If a machine key doesn’t exist in the web.config file of your existing application, you’ll need to generate a new key. IIS Manager includes a feature that generates machine keys (Figure 21-12). Alternatively, you can search the web to find online websites that can generate keys for you. Once you create a new key, add the machine-key entry to the section in both of your web.config files. Figure 21-13 shows how this looks.

745

Chapter 21 ■ Authenticating Your Users

Figure 21-12.  Generating a machine key in IIS7 manager

Figure 21-13.  Configuring your machine-key settings

Allowing Users to Log Out of Desktop Web Applications LightSwitch desktop browser applications don’t include a Log Out button, and the only way for a user to log out of a Forms-authenticated application is to close their browser. This behavior isn’t convenient for users who want to quit their session and to log in as a different user. In this section, I’ll show you how to add a Log Out button to make it easier for users to login with a different set of credentials.

746

Chapter 21 ■ Authenticating Your Users

When you create an application, LightSwitch creates a web page called LogOut.aspx in your server project. This web page provides the mechanism that allows HTML client users to log out of their sessions. To implement the same functionality in desktop browser applications, the technique that I’ll describe will call this page from a screen button. The first step is to add a reference to the System.Windows.Browser assembly in your desktop client project. Next, create a button on your screen called Logout and add the code shown in Listing 21-1. Make sure to include the imports or using statements that are shown in this listing. Listing 21-1.  Execution code for the Logout button

747

Chapter 21 ■ Authenticating Your Users

To test this code, you need to first deploy your application onto an IIS server. Once you deploy your application, copy the LogOff.aspx file from the root of your website into the DesktopClient subfolder. The code in this listing navigates the user to the LogOff.aspx page . This page terminates the user session and reloads your application. As a matter of good practice, the code in the CanExecute method  hides the Logout button if Forms authentication is not enabled, or if your application is not configured as a browser application. Figure 21-14 shows the appearance of the Logout button at runtime.

Figure 21-14.  Logout button on command bar

748

Chapter 21 ■ Authenticating Your Users

If you want to show a logout command that appears throughout your application, you can attach the logout code to a navigation menu, rather than to a button. To do this, you would create a dummy screen and add code to its _CanRun method. The “Opening Screens Conditionally at Login” section in Chapter 22 demonstrates this technique.

Summary Authentication enables you to determine the identity of your user, which in turn allows you to control what the user can do in your application. There are two types of authentication that you can use: Forms authentication and Windows authentication. Windows authentication is the most secure method for a two-tier desktop application. Windows authentication utilizes the credentials that your user inputs to log in to their Windows computer. The benefit of this method is that users don’t need to supply additional credentials when they start your application. Forms authentication is perfect for Internet applications, or for environments that don’t have a Windows domain. If you enable Forms authentication, LightSwitch prompts the user to enter a username and password at login. For both types of authentication, the administrator enters the user data through a screen that LightSwitch provides at runtime. LightSwitch uses the ASP.NET membership provider to manage your users. This provider stores your user data in tables inside your Intrinsic database. If you choose Forms authentication, your passwords must be eight characters in length and contain a non-alphanumeric character. You can change this rule by amending your web.config file. This file also allows you to configure how the provider encrypts the passwords in your database. You can share your Forms authentication credentials with other LightSwitch or ASP.NET applications by modifying your web.config file. This change will allow users to log in to different applications using the same username and password. To set this up, you need to amend the user, role, and profile providers in all systems so that they use the same authentication database and machine key. LightSwitch desktop browser applications don’t include a Logout button. So, if you want to add this ability, you can add a button to your screen to call a web page that logs off your user.

749

Chapter 22

Authorizing Your Users An important part of any application is security. To help secure your application, LightSwitch provides a security modal that you can use to control the actions of users. You can create server-based rules to restrict the data that various groups of users can view and update. And with desktop applications, you can limit the screens and controls that users can access. In this chapter, I’ll show you how to do the following: •

set up permissions, roles, users, and administrators in a system



limit access to data based on permissions



restrict access to screens and screen controls based on permissions

The core part of this chapter will describe how to implement server rules to prevent groups of users from viewing, updating, inserting, or deleting records. With desktop applications, you can prevent certain users from updating specific fields in a table, and you can also apply access control to entire screens and individual controls within a single screen. In this chapter, I’ll show you how to implement these features. To provide some practical examples, this chapter will show how you can prevent all users from using the system between midnight and 3 a.m. You will also find out how to dynamically change your application’s Start-up screen depending on the current user. Other examples include how to enable groups of users to bypass custom .NET validation and how to bind a list of usernames to a drop-down control.

Applying Permissions LightSwitch security depends on permissions, which you define at design time. Permissions define what your users can do. LightSwitch defines permissions in the same way that it defines screens and entities in your application. It defines permissions as LSML data within your application. At runtime, the system administrator creates roles and assigns permissions to those roles. Roles allow you to group together permissions, and you can assign the same permission to multiple roles. At runtime, the administrator also creates users and assigns the roles to users. Each user can belong to one or more roles. Figure 22-1 illustrates this relationship.

751

Chapter 22 ■ Authorizing Your Users

Figure 22-1.  Permissions are assigned to roles, and roles are assigned to users To restrict access to screens and data, you would write code that checks whether the logged-in user belongs to a role that has been assigned the required permission. Unlike permissions, roles and users are defined external to your application. Therefore, users can create users and roles, but they cannot define permissions. Figure 22-2 illustrates where permissions, roles, and users are defined.

Figure 22-2.  Here are where permissions, roles, and users are defined

752

Chapter 22 ■ Authorizing Your Users

■■Note A role can have any number of permissions assigned to it, and any number of users assigned to it.

Defining Permissions You define permissions through the Access Control section of your project’s properties page. Figure 22-3 shows an example set of permissions for an application. Let’s suppose you only want to allow managers to add and modify engineer records. You can accomplish this by defining a permission called CanEditEngineers. Once you add this permission, you can enforce this rule by writing code. I’ll describe the code you need to use as this chapter progresses.

Figure 22-3.  Adding permissions in the Access Control tab In the list that appears in Figure 22-3, notice the SecurityAdministration permission that appears at the top. The SecurityAdministration permission is a built-in permission. Users with this permission can create and modify the roles and users in your application.

■■Note To define permissions, you must enable Windows or Forms authentication. LightSwitch disables the Permissions grid if authentication is not enabled for your application.

Creating an Application Administrator Every application requires an initial administrator. The purpose of this administrator is to create additional users in your application. This user also needs to create roles and decide which permissions need to be added to those roles, and which roles are assigned to which users. For web applications that use Forms authentication, you can define the username and password of the administrator when you install your application in IIS. LightSwitch stores the username and password of the initial administrator in your web.config file (Figure 22-4). If your application contains no administrators when it first runs, LightSwitch uses the details in the web.config file to add the initial user.

753

Chapter 22 ■ Authorizing Your Users

Figure 22-4.  Specifying the initial user for your application For two-tier desktop applications, you can define the username and password of your administrator when you publish your application from Visual Studio.

Managing Roles and Users To manage roles and users, use an administrative account to log in to a desktop application. You can use any account that belongs in a role that’s been granted the SecurityAdministration permission. By default, you can find a link to the Roles screen in the Administration section of the navigation menu (Figure 22-5). This screen allows you to create roles and assign permissions to those roles. It also allows you to assign users to roles. The Users screen allows you to add, edit, and delete users.

Figure 22-5.  Roles screen Note that you can only manage roles and users through desktop applications. If you have an HTML client application and you want to define roles and users, you will need to add a desktop client to your application to allow you to access these two administrative screens.

754

Chapter 22 ■ Authorizing Your Users

Debugging Permission Code When you debug an application, LightSwitch won’t prompt you to log in, even when you enable authentication. So, to test that your application works as expected, you can assign yourself permissions at debug time by checking the “Granted for Debug” checkbox, which appears next to each permission row (as shown in Figure 22-3). LightSwitch grants you the permissions that you check while you run your application in debug mode. This enables you to test any security code that you add to your application.

Securing Server Objects In this section, I’ll show you how to define rules so as to limit the data that users can view and edit. With the exception of one item (which I’ll explain later), the content in this section applies both to desktop and HTML client applications. Because LightSwitch executes the code on the server, your access-control rules will apply when users access your data through OData or from Server Application Context code.

Applying Table-Level Access Control You can apply access control at the table (or entity-set) level to control whether a user can add, view, edit, or delete records in the table. All screens that bind to the table will honor the access-control rules that you define at the table. The benefit of this approach is that you can define your access-control rules in a single place, without the need to modify and carry out checks on every screen that consumes the data. To create access-control code, open your table in the table designer and click the Write Code button. Here, you can find a number of access-control methods, as shown in Figure 22-6. When you select a method, LightSwitch opens the code editor and creates a code stub in your data service class (that is: Server\ DataSources\ApplicationData\_ApplicationDataService.lsml.[cs|vb], or the equivalent data-service file).

Figure 22-6.  Entity-set access-control methods LightSwitch enforces the access-control rules on the server. The benefit of this is that if a user attempts to read or update data outside of a screen (via the OData endpoint, for example), LightSwitch still enforces your access-control rules. To prevent the current user from a performing an action, set the return value of the relevant access-control method to false. For example, to prevent the current user from deleting engineers, set the return value of the Engineers_CanDelete method to false.

■■Note Although this section uses the word table, the code I show you applies also to all entity sets from external data sources. Therefore, you can use the same techniques I show you in this section to control the actions a user can carry out in a SharePoint data source.

755

Chapter 22 ■ Authorizing Your Users

Restricting Users from Editing Data To illustrate how to apply security code, let’s look at how to build a rule to limit the users who can add, update, and delete engineer records. The code that I show you will restrict these operations to users who belong to roles that you grant the CanEditEngineers permission. All other users can view engineer records, but not update any details. To apply this rule, you need to add code to the Engineer_CanDelete, Engineer_CanInsert, and Engineer_CanUpdate methods. To add this code, open the Engineer table in the table designer, click the Write Code button, and add the code that’s shown in Listing 22-1. Listing 22-1.  Setting access-control permissions

756

Chapter 22 ■ Authorizing Your Users

To prevent a user from performing an action, you would set the return value of the respective access control method to false. For instance, you would set the return value of the [Table]_CanInsert method to false to deny a user the right to add rows to a table. The code in Listing 22-1 utilizes the Application.User object. This is a versatile object that provides many useful features. You can use it to return the full name of the current user and to return other useful authentication properties, as shown in Figure 22-7.

Figure 22-7.  IntelliSense options for the Application.User object An important method that this object exposes is the HasPermission method. This method accepts a permission value and returns whether the current user belongs in a role that includes the permission you supply. To make it easier for you to supply a permission value, LightSwitch provides a Permissions class that defines all the permissions in your application. As Listing 22-1 shows, you can refer to the CanEditEngineers permission by using the syntax Permissions.CanEditEngineers. If you write access-control code that prevents a user from deleting, inserting, or updating records, LightSwitch automatically disables any built-in buttons (in data grids, for example) that carry out these functions. However, if you create a custom screen command (e.g., button or link) to perform a data operation that you disallow in code, LightSwitch won’t automatically disable your button. You will need to write code in the screen command’s _CanExecute method to perform this task. An important point to remember when you write authentication code is to not perform access-control checks based on role membership. Because administrators define roles at runtime, you can’t guarantee that the role will exist. Therefore, you should always check against permissions and leave the task of managing roles and role permissions to the application’s administrative user.

Restricting Users from Reading Data You can prevent users from reading data by setting the result of the table’s CanRead method to false. If a user with insufficient permissions attempts to open a screen that contains a data grid, the data grid will display nothing except a red X. This behavior isn’t user friendly, so it’s good practice to write additional screen code to stop the user from opening the screen in the first place. When you use this technique to deny read access to a table, LightSwitch also disables access to the data inside the server pipelines. This reduces the possibility of any data “leakage.” Because LightSwtich applies the rule at the server, it also protects the data that it exposes via the OData endpoint. Therefore, a malicious user cannot circumvent your security by opening a browser and viewing the ApplicationData.svc page. If your server-side business logic requires access that the current user doesn’t have, you can override the restrictions by granting the necessary permissions in code. You would use the method Application.Current.User.AddPermissions.

757

Chapter 22 ■ Authorizing Your Users

■■Note Unfortunately, you can only call AddPermissions from code in the Save pipeline. If you try to call this method from any of the methods in the Query pipeline (e.g., PreProcessQuery), you’ll receive an exception. This behavior prevents you from denying all users read access to a table, and from only allowing access through queries (the queries would include permission-elevation logic that depended on the identity of the logged-on user).

Restricting Users from Saving All Data You can prevent users from saving data by setting the return value of the SaveChanges_CanExecute method to false. LightSwitch executes this method on the server when a user attempts to save data. Unlike the access-control methods that I’ve explained up until now, this single method applies to all tables in the data source. If the SaveChanges_CanExecute method returns false, the user won’t be able to save any data in any table at all. The logic that you write in any of these security methods is not only restricted to permission checks. You can also deny access based on other business rules. To give an example, the code in Listing 22-2 shows how you can use this technique to restrict access to your application between the hours of midnight and 3 a.m. Listing 22-2.  Preventing users from saving data

758

Chapter 22 ■ Authorizing Your Users

Restricting Users from Editing a Property There may be situations in which you want to prevent users from modifying specific fields in a table. You can accomplish this by setting the result of the property’s _IsReadOnly method to true (Figure 22-8).

Figure 22-8.  IsReadOnly method To demonstrate this technique, let’s look at how to restrict the users who can edit the problem description field in the Issue table. In this example, all users can view issue records, but only users who belong in roles with the CanChangeIssueDescription permission can modify the problem description. If a user lacks this permission, LightSwitch will render the problem description property as read only on all screens that show this property. Listing 22-3 shows the code that implements this rule. Listing 22-3.  Setting a property’s IsReadOnly method

759

Chapter 22 ■ Authorizing Your Users

In this listing, notice how the code checks whether the user is adding a new issue record by testing for an ID value of 0. If the user is adding a new record, it returns false to allow the user to create the problem description. A caveat of this technique is that the IsReadOnly method applies only to desktop applications. If you define a property as read only for a user and that user edits the property in an HTML client application, LightSwitch will allow the change to take place.

Applying Query-Level Permissions You can create rules to control the users who can execute a query. Each query includes a CanExecute method (Figure 22-9). Like the other examples in this section, you can prevent a user from executing a query by setting the return value of this method to false.

Figure 22-9.  A query’s CanExecute method To illustrate this method, let’s look at how to allow only users with the CanViewReport permission to execute a query called IssuesWithHighestFeedback. To implement this rule, add the code that’s shown in Listing 22-4 to the query’s CanExecute method. Listing 22-4.  Editing a query’s CanExecute method

760

Chapter 22 ■ Authorizing Your Users

Securing Client Objects In this section, I’ll describe access-control techniques that you can apply to your client. Because LightSwitch provides better support for desktop clients, this section focuses predominantly on desktop applications. In this section, I’ll show you how to control the users who can open specific screens. Next, I’ll show you how to restrict the use of buttons and commands on individual screens. 

Restricting Users from Opening Screens To control access to a screen, open your screen in the designer, click the Write Code button, and select the screen’s _CanRun method. This generates a method stub in LightSwitch’s client application class. To prevent users from opening a screen, set the result of the _CanRun method to false. To demonstrate this technique, let’s look at how to restrict access to the Engineer Management screen. The code that I will show you enables only users who belong in roles that are assigned the CanEditEngineers permission to open the screen. To implement this rule, open the screen in the designer and add the code that’s shown in Listing 22-5. Listing 22-5.  Setting a screen’s CanRun method

If a user attempts to open a screen (e.g., from a user-defined method) where the result of the _CanRun method returns false, the screen will not open. To help keep your navigation menu tidy, LightSwitch automatically filters the screens that are shown in the navigation menu. If a user has insufficient permissions to open a screen, LightSwitch hides the screen in the navigation menu.

Restricting Users from Clicking Links and Buttons Screen buttons and links bind to screen commands that appear in the screen member list of the screen designer. To prevent a user from executing a command, set the result of the command’s _CanExecute method to false. You can open the code editor by clicking the link in the command’s property sheet (Figure 22-10).

761

Chapter 22 ■ Authorizing Your Users

Figure 22-10.  Execute methods If a user lacks the permission to execute a command, LightSwitch automatically hides any buttons or links that bind to that command. In this example, the Issue Detail screen includes a link that opens a PDF report. This link should only be visible if the user belongs in a role that’s been assigned the CanViewReport permission. Listing 22-6 shows the code that carries out this rule. Listing 22-6.  Editing a command’s CanExecute method

762

Chapter 22 ■ Authorizing Your Users

■■Tip Although I show you how to use the CanRun method to enforce permissions, remember that you can also use this method to guard screen commands based on other conditions. Let’s suppose you create a method that generates Microsoft Word documents by using COM automation. If your application runs as a browser application (rather than as a desktop application), you can hide the button that carries out the Word automation by writing code in the CanRun method that checks AutomationFactory.IsAvailable.

Securing HTML Client Applications The access-control features that are available in HTML client applications are far more limited than their desktop client equivalents. First, there’s no way to control the users who can open screens. Unlike desktop applications, each screen doesn’t include a CanRun method you can use to restrict access to the screen. Any custom screen method that you create includes a CanExecute method (Figure 22-11). You can set the return value of this method to false to disable any buttons or controls that bind to the method.

Figure 22-11.  CanExecute code The HTML client does not implement a JavaScript equivalent of the .NET HasPermission method. Because of this, you can’t write JavaScript code to determine the permissions that the current user has. This makes it almost impossible to write meaningful client-side access-control code. You can probably devise a method to carry out more useful permission checks and to work around this problem. However, note that JavaScript is an interpreted client-side language. An end user can view any bespoke security code you writing by viewing the source of your web page. Because of this, it’s best to focus your efforts on applying security at the server level so as to secure HTML client applications.

763

Chapter 22 ■ Authorizing Your Users

Custom Authorization Examples Now that I’ve explained how the LightSwitch security model works, I’ll show you some practical security features that you can add to your application.

Associating Logins with Your Data As you’ve seen throughout this book, the sample Help Desk application stores engineer records in a custom table. When you enable authentication, LightSwitch stores the username and password combinations in a table that the membership provider manages. You can enhance your application by associating the records in your custom table with the usernames in the membership database. In our application, for example, you could use this enhancement to set default values or to open screens at start-up depending on the data that you store in the Engineer table. To build this functionality, the first step is to add a field to your Engineer table to store the engineers’ usernames. The next step is to build a screen to enable users to set the username for each engineer record. To assist with data entry, you can make it easier for users to enter a username by providing a drop-down list that contains a list of valid usernames. In this example, I’ll show you how to build a drop-down list control that binds to the security data. This control opens in a modal window that includes OK and Cancel buttons. When the user clicks the OK button, the code will update the engineer with the username that the user selects in the drop-down control. Figure 22-12 shows the end result of this example.

Figure 22-12.  Opening the modal window with a login name drop-down To create this screen, open an Engineer Details screen and carry out the following screen-design steps: 1. Use the Add Data button to add a new string property called LoginNameProperty. Uncheck the “Is Required” checkbox. 2. Add a new modal window control to your screen. You can use a columns layout group to place the Modal Window button to the right of the login name field. 3. Drag the LoginName property onto your screen. Change the control type to a custom control and set the custom control type to a combo box. Add OK and Cancel buttons to your modal window control. Name your buttons OkModalWindow and CloseModalWindow respectively. Figure 22-13 shows the design-time view of your screen.

764

Chapter 22 ■ Authorizing Your Users

Figure 22-13.  Design-time view of Username Picker screen Now, add the code that’s shown in Listing 22-7. Once you deploy your application and set up some users, you’ll be able to use the drop-down control to enter users.

765

Chapter 22 ■ Authorizing Your Users

Listing 22-7.  Adding a username combo box

766

Chapter 22 ■ Authorizing Your Users

Let’s look at an explanation of this code. The code that runs on initialization uses the DataWorkspace. SecurityData object to obtain a list of usernames . The UserRegistrations collection returns the username data, and the next block of code sets the data source of the drop-down to be a list of usernames . The code that runs when the user clicks the OK button sets the LoginName of the engineer record to the login name that the user selects in the drop-down . The code that runs when the user clicks the Close button simply calls the CloseModalWindow method to close the modal window . As a side note, the DataWorkspace.SecurityData object provides many useful features you can use, including properties you can use to determine the role membership and permissions of a given user. You can even call a method to change the password of a user. Figure 22-14 shows some of the features that the SecurityData object provides.

767

Chapter 22 ■ Authorizing Your Users

Figure 22-14.  The SecurityData object provides many useful features

■■Note If you deploy an HTML client application to SharePoint, you can use the built-in person-picker control to select users. Typically, SharePoint users map to Active Directory users in on-premises installations of SharePoint.

Opening Screens Conditionally at Login The ability to configure the Start-up screen of an application in code can be very useful. In typical business applications, different groups of users often focus on different tasks. Therefore, you can make your application more user friendly by showing a Start-up screen that is relevant to the user who logs on. To demonstrate this technique, I’ll show you how to customize the start-up routine of your application based on the engineer who logs in. If the engineer who logs in has the CanViewAllIssues permission, the application opens a screen that is suitable for managers. For all other engineers, the application opens a regular Start-up screen. As a prerequisite to this section, create a set of screens for managers and non-managers. Name your screens EngineersManagerGrid and EngineerDashboard respectively. You may have created these screens earlier in this book. Now, carry out the following steps: 1. Create a new screen by using the New Data Screen template. Leave the Screen Data drop-down blank and name your screen StartUp. 2. Click the Write Code button, select the Startup_CanRun method, and enter the code that’s shown in Listing 22-8. 3. Open the properties of your application and use the option in the Screen Navigation tab to set your Start-up screen to StartUp.

768

Chapter 22 ■ Authorizing Your Users

Listing 22-8.  Opening screens conditionally

769

Chapter 22 ■ Authorizing Your Users

At this point, you can run your application and see how the Start-up screen changes depending on the permissions of the user who logs in. This technique utilizes the screen’s CanRun method  rather than the IntializeDataWorkspace or Activated method. If you were to use one of these screen methods, the user would see the Start-up screen appear prior to the code opening the desired screen. If the user has the CanViewAllIssues permission , the code opens the manager screen. If not, it retrieves the engineer ID that relates to the logged-in user . Because this code runs outside the context of a screen object, it needs to create a data workspace to perform this query. If the code finds the engineer, it opens the Dashboard screen for the engineer. In this example, ShowEngineerDashboard includes a parameter you can use to set the data that the screen shows. Finally, the code sets the return value of the CanRun method to false  to cancel the opening of the Start-up screen.

Configuring the Start-up Screen in HTML Applications With HTML client applications, you can specify the Start-up screen through the JavaScript method that starts your application. The default entry point to an HTML client application is the default.htm web page. Toward the bottom of this file, you can find the code that starts your application. This method is called _run, and as Figure 22-15 illustrates, you can specify the screen name that your application shows when it starts.

Figure 22-15.  Contents of Default.htm file A technique that you can use to customize your Start-up screen is to replace the default.htm page with an ASP.NET page. Once you do this, you can write .NET code that emits JavaScript to start your application with a specific screen. If you add login controls to your .NET page, you can write .NET code that chooses the Start-up screen based on permissions or other server-side logic.

770

Chapter 22 ■ Authorizing Your Users

Restricting Row-Level Access to Data Another common business requirement is the ability to restrict which rows from the table that a user can see. To demonstrate how to build this feature into your application, let’s look at how to configure the Help Desk system so that engineers can only view the issue records that are assigned to them. The best way to enforce this rule is to apply your access-control rule on the default All query. This is because all queries that return issue records ultimately call the default All query. Therefore, LightSwitch will always execute the code that you define here every time you return data from the issues table. To create this example, open the issues table in the table designer. Click the Write Code button and select the Issues_Filter option. Add the code that’s shown in Listing 22-9. Listing 22-9.  Restricting row-level access to data

771

Chapter 22 ■ Authorizing Your Users

Let’s review how this code works. The first part checks whether the user has the CanViewAllIssues permission. If the user doesn’t have this permission, the code obtains the currently logged-in engineer . Next, it applies a filter to only return only the records where the assigned-to engineer of the issue record matches the engineer who is logged in . It’s very important to note that if an engineer retrieves issue records through a navigation property, the data-retrieval process bypasses the default _all query. If an engineer can view other engineer records on a screen that shows related issues, the engineer can view the issue records that should not be visible. Another important point is that if an engineer updates a record that someone else has updated, the concurrency-error window that appears could contain data that shouldn’t be seen by the engineer.

■■Caution If you need to restrict the data that a user can see, make sure to test your application to make sure that data leakage doesn’t occur in the way that I have described.

Setting Screen Control Properties by Permission Another way in which you can enhance your application is to hide screen controls based on the current user. In this section, I’ll use the issue Search screen to demonstrate this technique. This screen includes an auto-complete box control that allows the user to filter the results by assigned engineer. I’ll show you how to configure this screen so that users with the CanViewAllIssues permission have full access to the autocomplete box. I’ll also show you how to configure the Search screen to only return records for the current user if that user lacks the CanViewAllIssues permission. We’ll accomplish this by setting the selected item in the auto-complete box to the current user, and we’ll then prevent the user from changing the selected item by making the control read-only. The prerequisite to this example is to create a Search screen for the issue table if one doesn’t already exist. Name your screen IssueSearchAll and configure it so that it filters the results by a property called EngineerSelectionProperty. Now, click the Write Code button, select the InitializeDataWorkspace method, and enter the code that’s shown in Listing 22-10.

772

Chapter 22 ■ Authorizing Your Users

Listing 22-10.  Configuring screen controls by permission

Let’s look at how this code works. If the user doesn’t have the CanViewAllIssues permission, the code obtains the currently logged-in engineer . It then sets the selected item of the AutoCompleteBox to this engineer and disables the control by setting the IsEnabled property to false .

773

Chapter 22 ■ Authorizing Your Users

Allowing Users to Bypass Validation In the final example of this chapter, I’ll show you how to allow specific users to bypass custom validation. Typically, you would use this technique to enable special users to carry out changes that normal users cannot perform. For example, let’s suppose you create a rule that prohibits users from entering a close date for an issue record without selecting the engineer who closed the issue. It’s possible to configure your validation code to relax this rule for managerial users. To implement this technique, you can simply amend your .NET validation code to only apply a rule based on whether the current user has a particular permission. This simple technique requires you to modify every validation rule that you have defined on a table. An alternative technique is to write code in a table’s _AllowSaveWithErrors method. If you set the return value of this method to true, the current user can save changes irrespective of any validation failures in the record. You can use this technique when you want a user to be able to circumvent all validation rules in a table, as opposed to just specific rules in a table. To illustrate this technique, let’s look at how to implement a rule to allow users with a permission called CanBypassValidation to save changes to the Issue table without adhering to any custom .NET validation rules. To implement this rule, open the Issue table, click the Write Code button, and select the Issue_AllowSaveWithErrors method. Enter the code as shown in Listing 22-11. Listing 22-11.  Bypassing validation

If you now run your application and log in as a user with the CanBypassValidation rule, you’ll be able to save your changes without adhering to the validation rules. Although this code allows the user to bypass any custom .NET validation rules, LightSwitch still honors the validation rules that your data layer defines (for example, SQL Server check constraints).

774

Chapter 22 ■ Authorizing Your Users

Summary In this chapter, I showed you how to secure your application. With LightSwitch, you can restrict access to tables, rows, queries, screens, and individual controls on screens. LightSwitch security comprises three types of objects: permissions, roles, and users. For each application, you create permissions to define the access rights. The developer defines permissions, and LightSwitch stores these in LSML format inside a file called service.lsml. In contrast, the system administrator defines roles and users at runtime. LightSwitch stores roles and users in the Intrinsic database. Roles allow you to group together permissions. The system administrator assigns permissions to roles; it’s possible to assign the same permission to multiple roles. To configure the actions that each user can carry out, the system administrator assigns roles to users. Each user can belong to one or more roles. At the server, you can apply access rules to tables and queries. With tables, you can limit the users who can view and edit data. For each table, you can write .NET code in the [TableName]_CanRead method to define the users who can view the data in the table. To prohibit a user from viewing data in the table, you would set the return value of this method to false. The general pattern you use to enforce rules is to test if the current user has a permission by calling the Application.User.HasPermission method. To check for a specific permission, you would pass the permission name to this method. You can use the result of this method to set the return value of the [TableName]_CanRead method. To prohibit a user from editing data, you would write code that sets the return value of the [TableName]_CanDelete, [TableName]_CanInsert, and [TableName]_CanUpdate methods. To prevent a user from deleting, inserting, or updating, you would set the return value of the respective method to false. For each data source, LightSwitch exposes a method called SaveChanges_CanExecute. You can prevent a user from saving changes to all tables in the data source by setting the return value of this method to false. In the case of desktop applications, all screens expose a method called [ScreenName]_CanRun. You can prevent a user from opening a screen by setting the return value of this method to false. If a user has insufficient permissions to open a screen, LightSwitch will hide the menu item that opens the screen in the navigation menu. At a screen level, each button on a screen exposes a method called [CommandName]_CanExecute. You can prevent a user from executing a button by setting the return value of this method to false. Unlike desktop applications, the HTML client does not have a JavaScript method you can call to determine the permissions of the current user. Therefore, with HTML client applications, you cannot easily prevent users from opening screens or clicking buttons based on permission. In the final part of this chapter, I demonstrated security features you can add to your application. If your application contains a custom table that stores user data, you can build more-useful applications if you have some way to link your user data with the LightSwitch login names. To retrieve a list of usernames, you can use the methods that LightSwitch exposes through the DataWorkspace.SecurityData object. I showed you how to use this method to create a drop-down list that shows a list of users. I then showed you how to use this control on a screen to associate users with engineer records. Next, I showed you how to customize your application’s Start-up screen based on the current user. You can implement this technique by creating a “dummy” Start-up screen. This Start-up screen includes code in the CanRun method that conditionally opens an actual Start-up screen based on the current user. A common requirement is the ability to limit the rows that a user can view in a table. You can implement this feature by writing code in the Filter method of table. You would write .NET code to filter out the records that you don’t want the user to see. Any query that returns data from this table will apply the filter that you specify in this method. The benefit of this technique is that you can apply your rule in a single place, rather than add code to every query that returns data from the table. An important caveat to this technique is that the code doesn’t apply to data that a user accesses via a navigation property or to data that LightSwitch displays in the concurrency error dialog. Therefore, it’s important to exercise some caution when you use this method. Finally, I showed you how to create a permission that allows a user to override all the custom validation rules in a table. You can implement this technique by writing code in the table’s AllowSaveWithErrors method. Within this method, you can check a user’s permissions and set the return value of this method to true so as to allow the current user to save data, even when validation errors exist in the data.

775

Part iX

Going Live with Your Application

Chapter 23

Deploying Applications In the final chapter of this book, I’ll show you how to deploy your application. In this chapter, you’ll find out how to do the following: •

use the publish wizard to deploy both desktop and web applications



set up and configure a web server



publish your applications onto Windows Azure

There are many ways for you to deploy an application, and the method that you choose depends on your application type and infrastructure. This chapter will explain all the possible options and show you exactly how to carry out a deployment.

Getting Started with Deployment Deploying a LightSwitch application can be difficult. This is because LightSwitch allows you to create HTML client or Silverlight applications that can run on either the desktop or web. It also relies on the application services that can run on a server, Azure, or the client workstation (in the case of a desktop application). This combination results in several distinct deployment scenarios, each with a unique set of installation tasks. Figure 23-1 highlights the choices in the form of a flow diagram and shows you the main tasks that you need to carry out. You can use this diagram to help identify the sections in this chapter that you should focus on. For example, you can ignore the sections on setting up Internet Information Services (IIS) and ASP.NET if you want to deploy a desktop application and install your application services on the workstation.

779

Chapter 23 ■ Deploying Applications

what’s your application type?

Start

Browser/ Data Service Only

Desktop

Client Task: Install Silverlight Runtime

Certificate Task: Obtain/Purchase SSL Certificate (optional)

Certificate Tasks: Purchase Client Side cert (optional) Do you want to host your application on Windows Azure? Do you want to install application services on the workstation?

YES

Databaset Task: Install SQL Server

NO

YES

Azure Tasks: Create Azure Account Create a Website or Cloud Service Create a SQL Azure Database

NO Databaset Task: Install SQL Server

Development Task: Run Publish Wizard

Development Task: Install IIS Install ASP.NET Install Deployment Toolkit

Development Task: Run Publish Wizard

Development Task: Run Publish Wizard

Databaset Task: Runs script so create your SQL Database

Do you want to package or publish your Application? PACKAGE

PUBLISH

Deployment Task: Install Package on Webserver Deployment Task: Run Setup.exe on Desktop

Finish

Figure 23-1.  Deployment steps The rest of this chapter is arranged as follows. I’ll start by describing the underlying principles of deployment, and then show you how the Publish wizard works. If you want to publish a web application, you’ll need to set up a web server before you run the Publish wizard. The next part of this chapter will show you how to install IIS, and then will show you how to work with the output that the Publish wizard generates.

Choosing an Application Topology LightSwitch depends on application services that can run in IIS, Windows Azure, or the end user’s machine. If you want to deploy a Silverlight or HTML client web application, you must host your application services in IIS or Windows Azure. However, if you want to deploy a Silverlight desktop application, you have the

780

Chapter 23 ■ Deploying Applications

option to host the application services on the local machine. This configuration is called a “two-tier” setup. The advantage of running the services locally is that it’s easier to set up. Unlike a “three-tier” setup, you don’t need to go through the tricky process of setting up a web server, or understand how Windows Azure works. But the disadvantage is that you need to install the services on every machine where your application runs. Two-tier applications are therefore more suitable for single-user applications or applications that don’t have many users. In this type of deployment, you can also choose to install the database on the end-user machine by using a local instance of SQL Server or SQL Express. This means that you can run your entire application from a single machine.

Choosing Whether to Publish or Package If you want to host your application services in IIS, you can choose either to publish or to package your application (Figure 23-2).

Figure 23-2.  Publishing versus packaging If you choose to publish your application, LightSwitch deploys it directly from Visual Studio onto your IIS server. It’s very easy to publish an application, but you need to carry out more work to prepare your IIS server beforehand. The operating systems that support publishing are Windows Server 2008 SP2 or above, and Windows 7 or above. The second option is to package your application. Packaging produces a set of installation files that you manually copy and install on your server. Packaging an application is easier than publishing. There are fewer tasks to carry out on your web server, and you don’t need to struggle to make Visual Studio communicate with IIS. For example, your application will fail to publish if a firewall blocks the ports that the publishing process requires (port 8172 by default). If you develop your application on a machine that isn’t on the same domain as the server that you want to deploy to, packaging is a good choice.

Setting Up Your Workstations In order to set up a workstation to run LightSwitch, there are actually very few tasks to carry out. HTML client applications require only a web browser, so in almost all cases, you don’t need to carry out any additional work. Silverlight applications require the Silverlight 5 runtime. If a user doesn’t have the runtime installed and attempts to run a Silverlight browser application, the application displays a web page that prompts the user to download the Silverlight runtime from the Microsoft website. In corporate environments, you can distribute the Silverlight runtime by using group policy, SMS (Microsoft Systems Management Server), or some other software distribution mechanism. Some companies have policies in place that block Silverlight or Adobe Flash. If you have a policy like this in place, your Silverlight LightSwitch application will simply not work.

781

Chapter 23 ■ Deploying Applications

Setting Up SQL Server In all deployment scenarios, you need a database server with SQL Server 2008 or above to host your application. If you wanted to deploy your application into Windows Azure, you would need to create an SQL Azure database rather than carry out an on-premises installation of SQL Server. If you want to deploy a two-tier desktop application, you can install SQL Server Express on the client and run your entire application on the workstation. This type of setup is ideal for single-user or stand-alone applications. SQL Server Express is a free edition of SQL Server, and it’s perfect if you don’t have a license for a higher, paid-for edition of SQL. A disadvantage of SQL Server Express is that it limits performance by placing restrictions on the amount of memory and CPU cores that the database engine can use. You can find out more and download SQL Express from the following website: http://www.microsoft.com/en-us/ server-cloud/products/sql-server-editions/sql-server-express.aspx A detailed explanation of SQL Server is beyond the scope of this book, but if you want to find out more, SQL Server Books Online (BOL) is an excellent resource: http://msdn.microsoft.com/en-us/library/ ms187875.aspx For the purpose of installing LightSwitch, the topics that you should be familiar with are the following: •

installing an instance of SQL Server and using Management Studio



creating databases, logins, and users



understanding SQL/Windows authentication and knowing how to create an ADO. NET connection to your database

■■Tip LightSwitch stores your intrinsic (Application Data) data in SQL Server. When you enable authentication, it also stores role and user data in your Intrinsic database. It’s important to back up your SQL Server database, as this allows you to restore your application’s data in the event of a disaster. You can refer to Books Online to find out more about how to back up and restore an SQL Server database.

Using the Publish Wizard The Publish wizard is a tool that guides you step by step through the deployment process. You can use the wizard to package or publish your application onto IIS, or to publish your application into Windows Azure. To start the Publish wizard, right-click your project in Solution Explorer and select the “Publish” menu item. The first page prompts you to select exactly what you want to install (Figure 23-3). You can install your complete application or just the data service. If your application contains desktop and HTML clients, the “Complete Application” option will publish both clients.

782

Chapter 23 ■ Deploying Applications

Figure 23-3.  Choosing your application type Notice how the wizard shows a warning message if you set your active configuration to Debug. When you publish an application, you should set the active configuration of your application to Release by using the drop-down menu that appears in Visual Studio’s toolbar. The second page in the wizard allows you to specify where you want to host your server components, as shown in Figure 23-4. As I mentioned earlier, you can host your application services in either IIS or Azure. In the case of a desktop application in desktop mode, you have the option to host your application services locally. If your LightSwitch solution includes both desktop and HTML clients, you’ll no longer have the option to deploy your application services locally. Therefore, make sure not to add an HTML client to your solution if you want to run your application services locally.

783

Chapter 23 ■ Deploying Applications

Figure 23-4.  Choosing where to host the application’s services The remaining steps in the wizard are self-explanatory. In the remainder of this section, I’ll explain the more important steps in greater detail.

Data Connections Page If you choose to publish your application, the wizard shows the Data Connections page, illustrated in Figure 23-5. This page prompts you for two connection strings. The first connection string specifies the connection that LightSwitch uses to connect to your Intrinsic database at runtime. The wizard uses the second connection string during the publishing stage to create and/or update your Intrinsic database. The buttons next to the connection string textboxes open a dialog that you can use to build a connection string.

784

Chapter 23 ■ Deploying Applications

Figure 23-5.  Data connection settings for published output Figure 23-5 highlights the warning that the wizard shows when you enter a connection string that uses integrated security. The Publish wizard allows you to specify only connection strings that use SQL Server authentication. If you’re not happy with this type of authentication, I’ll show you later in this chapter how to manually set up your application so that it uses integrated security. If you choose to package your application rather than publish it, the wizard shows the page that’s shown in Figure 23-6. This page allows you to create a new Intrinsic database or to update an existing database.

Figure 23-6.  Data connection settings for packaged output

785

Chapter 23 ■ Deploying Applications

You would choose the option to update an existing database if you want to update an existing application. When you choose this option, you’ll need to provide a connection string. This allows the wizard to compare your database schema against the existing database and to create an update script. You might wonder why the wizard doesn’t prompt you to supply database credentials at this point. This is because LightSwitch asks you for the credentials when you actually install the package, and by doing this, it avoids persisting your sensitive credentials in a package file that someone else could get hold of.

Prerequisites Page If you deploy a two-tier desktop application, you can specify your application’s dependencies using the page that’s shown in Figure 23-7. By default, your setup package includes the LightSwitch prerequisite component, which allows LightSwitch to host your application services without IIS being available.

Figure 23-7.  Install Prerequisites dialog In addition to the LightSwitch prerequisites, you can also specify additional prerequisites by choosing the “Yes, I need to specify additional prerequisites” radio button and using the checkboxes to select the items that you want to include. When you do this, the wizard automatically includes the .NET 4 Framework and Windows Installer 4.5 packages. LightSwitch requires the .NET 4 Framework to run, and Windows needs the Windows Installer to install the .NET 4 Framework. The final set of radio buttons allows you to specify the installation location for your prerequisites. You can select the option that prompts the user to download the prerequisites from the Internet if you want to reduce the file size of your setup package. The LightSwitch wizard doesn’t allow you to include your own prerequisites. For example, the wizard allows you to add Microsoft SQL Server Express 2008 R2 and 2012. But if there are any other components that you want to include, there isn’t any option for you to add them to this list.

786

Chapter 23 ■ Deploying Applications

Security Page If you enable authentication in your application, you can use the Application Administrator tab to specify your initial application administrator. Figure 23-8 shows the page that appears when you enable Forms authentication through the properties of your LightSwitch project for a two-tier deployment. If you enable Windows authentication, the wizard doesn’t show the full name and password textboxes. Instead, it prompts you to enter only a domain username. In the case of Windows authentication, make sure that you enter your administrator’s username in a format that includes your domain (for example, DOMAIN\TIM). If you omit the domain specifier, LightSwitch assumes that you’re referring to a local Windows user on your database server. For three-tier deployments, the option to specify the username and password will not appear. You can specify these details when you install the output into IIS.

Figure 23-8.  Application Administrator dialog (for two-tier desktop applications) If you want to update an application that you’ve already deployed, choose the radio option that specifies that an application administrator already exists.

Digital Signature/Certificate Page When you publish a Silverlight application, you can optionally specify a certificate. But what’s the purpose of a certificate, and why would you want to add one? A digital certificate allows you to sign your application’s XAP file—this is the compiled Silverlight application that runs on the end-user’s machine. Signing a XAP file verifies the authenticity of your application and makes it difficult for a hacker to tamper with your application without it being noticed. If you don’t sign your application, Windows shows a warning when the user installs a Silverlight Desktop application. This warning states that Windows can’t verify the publisher and that your application might be harmful (Figure 23-9). Your users might be alarmed by this warning, so it’s a good idea to sign your application with a certificate.

787

Chapter 23 ■ Deploying Applications

Figure 23-9.  Warning dialog shown during installation Figure 23-10 illustrates the page that allows you to specify a certificate and sign your application. You can purchase a certificate from a third-party company such as VeriSign or use an internal certificate server if your company has one in place. If you want test the process of signing an application, you can generate a self-signed certificate by using a utility called makecert. You can read more about this and find out the command-line switches that you can use by visiting the following MSDN page: http://msdn.microsoft. com/en-us/library/bfsktky3%28v=vs.80%29.aspx

Figure 23-10.  Dialog for specifying a certificate The final page that the wizard shows is the summary page. You can use this page to review your settings and to complete the publishing or packaging process.

788

Chapter 23 ■ Deploying Applications

Setting Up Your Web Server Now that you understand how the Publish wizard works, we will review how to set up and configure a web server. A web server is necessary for browser applications and requires you to carry out the following tasks, which I’ll fully describe as this section progresses: 1. Install the .NET 4.6 Framework. 2. Install the IIS web server. 3. Install Web PI and the Web Deploy tool. 4. Configure Application pools. 5. Optionally, set up SSL. The version of IIS that you’ll set up depends on your server’s operating system, and in this section I’ll show you how to install LightSwitch on Windows 2008 through to Windows 2012.

Installing the .NET 4.6 Framework The first task to carry out on your web server is to install the Microsoft .NET Framework 4.6. You can download this from the following address on the Microsoft website: http://www.microsoft.com/download/en/details.aspx?id=17718 On Windows 8 and Windows 2012, a prerequisite of the Microsoft .NET Framework 4.6 is Windows Update KB 2919355. The .NET Framework Installer prompts you to install this update if it is missing from your machine.

Setting Up IIS on Windows Server 2012/2008 Windows 2008 comes with IIS7, whereas Windows 2012 includes IIS8. With both of these operating systems, you can add IIS through the Server Manager utility. To do this, open Server Manager, go to the Roles Summary group and click the Add Roles link (shown in Figure 23-11). This opens the Add Roles wizard, and you can find a page in this wizard to select the Web Server (IIS) server role.

Figure 23-11.  Adding the IIS server role

789

Chapter 23 ■ Deploying Applications

When you complete the Add Roles wizard, Server Manager adds a Web Server (IIS) section inside the Roles group, as shown in Figure 23-12.

Figure 23-12.  Adding role services in Windows 2012 In the Role Services pane, enable the following three role services, as highlighted in Figure 23-12: •

Management Service



Application Development ➤ ASP.NET (version 4.6)



Security ➤ Windows Authentication

The screenshots in this section illustrate the steps for Windows 2008. Windows 2012 provides a simpler interface, as it combines the Role and Role Services settings into a single dialog.

790

Chapter 23 ■ Deploying Applications

Setting Up IIS on Windows 7 and Above With client operating systems, you can add IIS through the Windows Features dialog, which you can access via Control Panel. The options that you need to select beneath the Internet Information Services ➤ World Wide Web Services node include: •

Application Development Features ➤ ASP.NET 4.6



Common HTTP Features ➤ Default Document



Common HTTP Features ➤ Static Content

To configure ASP.NET, you should check the HTTP Activation item that appears beneath the .NET Framework 4.6 Advanced Services ➤ WCF Services node (Figure 23-13). You need to check this option in order to enable your SVC service endpoint (for example, http://myWebServer/LightSwitchApp/ ApplicationData.svc) to return data.

Figure 23-13.  Configuring WCF services

Configuring the Web Deploy Tool To publish an application from Visual Studio or to install the packages that the Publish wizard generates, you need to install the Microsoft Web Deploy tool. The simplest way to install this is to use the Web Platform Installer (often abbreviated to Web PI). IIS Manager prompts you to install Web PI when it starts. If it doesn’t, you can download and install it through the following link: http://www.microsoft.com/web/downloads/ platform.aspx When Web PI starts, you can use the search feature to find and add the “Web Deploy 3.5” item (Figure 23-14). Although a higher version of Web Deploy exists (v3.6), this version does not include the menu item that installs packages into IIS. Therefore, you should choose version 3.5.

791

Chapter 23 ■ Deploying Applications

Figure 23-14.  Installing the prerequisites using Web PI When you install the Web Deploy tool, the installer adds a Web Deployment Agent Service (Figure 23-15). To publish applications from Visual Studio, make sure that Windows starts this service. If your application fails to publish, a possible cause is that this service may not have started correctly.

Figure 23-15.  The Web Deployment Agent Service must be started

Setting Up IIS Application Pools Application pools improve the reliability of your web server by isolating the applications that run in IIS. If a website in an application pool crashes, it won’t bring down the other websites that run in other application pools. It therefore makes good sense to deploy each LightSwitch application into its own separate application pool. Each application pool also runs under a specific security context, which enables you to configure your application services to connect to your SQL Server database through Windows Authentication. Figure 23-16 illustrates this concept.

792

Chapter 23 ■ Deploying Applications

Figure 23-16.  Set up an application pool so as to Windows authenticate to SQL Server To create a new application pool, open Internet Information Services (IIS) Manager and right-click the Application Pools node on the navigation menu on the left. You’ll find a right-click context-menu option that allows you to create a new application pool, as shown in Figure 23-17. It’s important to set up your application pool to use version 4.6 of the .NET Framework. In IIS7 and above, it is also preferable to choose Integrated Managed Pipeline Mode, as opposed to Classic Mode. Classic mode is primarily designed for legacy code that might not run properly in integrated mode. Your LightSwitch server runs more efficiently when you set the pipeline mode to integrated.

Figure 23-17.  Creating an application pool in IIS7 After you deploy your website, you can set it to use the application pool that you added by modifying the website properties in IIS Manager.

793

Chapter 23 ■ Deploying Applications

Configuring SQL Server for Windows Authentication Your LightSwitch application services can authenticate to SQL Server through two types of authentication: SQL Server authentication or Windows authentication. SQL Server authentication uses SQL Server to store and manage the login and password credentials. If you use SQL Server authentication, you need to hard-code your SQL server login and password in the connection string that LightSwitch uses to connect to your database. Because your login name and password are hard-coded in a plain-text file, some IT departments regard SQL authentication as being less secure than Windows authentication. If you want to read more about the pros and cons of SQL Server authentication versus Windows authentication, you can find out more in the following TechNet article: http://technet.microsoft.com/en-us/library/ms144284.aspx. To use Windows authentication, you need to first create a Windows domain user. If your IIS Server and SQL Server are on the same machine, you might find it easier to create a local Windows user rather than a domain user (particularly if you don’t have sufficient permissions to create new domain users). Select the application pool that your application uses and open the Advanced Settings dialog. Open the Application Pool Identity dialog by clicking the button next to the Process Model ➤ Identity textbox. When the dialog opens, choose the “Custom account” radio button (Figure 23-18) and use the Set button to specify the Windows user account you want to use.

Figure 23-18.  Changing the application pool identities The Windows user you specify needs to have NTFS read permissions on the folders where you install your LightSwitch application. You should also add the user to the local IIS_IUSRS group in order to grant access to the necessary ASP.NET resources. The last step is to make sure that you add an SQL Server login for your Windows user by using SQL Server Management Studio. You’ll need to grant access permissions to the tables in your application as well as grant access rights to the tables that the ASP.NET membership provider uses. The quickest way to do this is to add your user into the following database roles:

794



aspnet_Membership*



aspnet_Roles*



db_datareader



db_datawriter



public

Chapter 23 ■ Deploying Applications

Windows authentication should now work, but if it doesn’t, you might need to configure the NTLM provider or carry out some extra steps to configure authentication. The following TechNet article will help you if you encounter problems: http://technet.microsoft.com/en-us/library/dd759186.aspx.

Configuring Secure Sockets Layer (SSL) The LightSwitch client communicates with your web server via the HTTP protocol—a clear-text protocol. A hacker who monitors your network can see your LightSwitch data as it passes through the network. This poses a security vulnerability, particularly if your application uses Forms authentication. A hacker can easily discover username and password combinations by monitoring the network while users log in. To mitigate this risk, you can encrypt your data by using the HTTPS protocol. To set up HTTPS, you need to install an SSL (Secure Sockets Layer) certificate on your web server. This certificate verifies the identity of your server and contains the keys that SSL uses for encryption. You can either purchase a certificate from a third-party company, such as VeriSign, or use an internal certificate server if your company has such infrastructure in place. The Server Certificates and Site Binding options in IIS Manager allow you to request, install, and configure SSL certificates. An SSL certificate is valid when it meets the following three conditions: the server name on the certificate matches the server on which it’s installed, the certificate is within its validity period, and the certificate is signed by a trusted certificate authority. What tends to happen is that administrators allow certificates to expire by not renewing them in time. It’s important not to let this happen, because desktop applications won’t work if your web server’s SSL certificate becomes invalid. The security model in Silverlight prevents LightSwitch applications from connecting to web servers with invalid certificates, and there’s no way that you can circumvent this security feature. Silverlight browser and HTML client applications will still work, but the browser warns the user that they “might be visiting a dangerous website.” This doesn’t look professional, so it’s good practice to make sure that your SSL certificates don’t lapse. If your application stores sensitive data, you might want to mandate encryption on all network traffic that takes place between your client and the server. This is particularly useful on LightSwitch applications that you expose over the public Internet. You can mandate SSL for all traffic by modifying your web.config file as shown in Listing 23-1. When you deploy your application, you can find this file in the root folder of your ASP.NET application. Listing 23-1.  Web.config setting to mandate SSL

Installing the Packages Now that we’ve covered the server configuration tasks, let’s look at how to install the output from the Publish wizard.

Installing a Two-Tier Desktop Application When you use the Publish wizard to build a two-tier desktop application, the wizard produces a set of installation files in the output folder that you specify in the wizard. The publish output includes a file called Setup.exe, which is the application that you would run on the client workstation to install your application.

795

Chapter 23 ■ Deploying Applications

If you specify any prerequisites in the Publish wizard (such as the Microsoft .NET Framework), Setup.exe will install these components too. But before you run Setup.exe, you need to carry out the following data tasks: 1. Install your SQL Server database. 2. Modify your application’s database connection string.

Installing Your SQL Database The output from the Publish wizard produces an SQL script called .sql (where is the name of your LightSwitch application). This script creates the database, tables, stored procedures, and other database objects that support your application. You need to execute this script on your database server, either by using the sqlcmd command-line tool or SQL Server Management Studio. If you have a basic instance of SQL Server Express without the Management Tools, sqlcmd is the method that you would use. For SQL 2012 Express, the default location of this utility on a 64-bit machine is Program Files(x86)\Microsoft SQL Server\110\Tools\Binn. To use sqlcmd, open an elevated command prompt, navigate to the directory where it’s installed, and run the following command: sqlcmd.exe -i Helpdesk.sql -S .\SQLExpress You will need to replace the arguments that you supply to sqlcmd.exe as follows: •

-i Helpdesk.sql: This specifies the SQL file that you want to execute. Replace this with the name of the SQL file in your publish folder.



-S .\SQLExpress: This specifies the name of your database server and SQL Server instance.



-U -P : If you don’t specify the –U and – P switches, sqlcmd connects to your SQL Server instance using Windows authentication. These switches allow you to supply a username and password if you want to use SQL authentication instead.

If you choose to install the SQL script using SQL Server Management Studio, make sure to place your query window into SQLCMD mode by selecting the option in the Query menu. Your script won’t run correctly if you don’t do this. Note that with SQL Server 2014, you must select the “Management Tools” option in SQL Setup to include sqlcmd. Because of this, it’s simpler just to use SQL Management Studio rather than sqlcmd with SQL Server 2014.

Setting the Database Connection String If you specified a correct and valid connection string in the Publish wizard, you can skip this step. But if not, you need to modify your application’s connection string so that it refers to the database that you installed. The Publish output contains an Application Files subdirectory that includes a file called web.config. Open this file in Notepad and edit the connection string value in the section like so:

Replace SERVERNAME\SQLEXPRESS with the name of your database server and instance, and replace HelpDeskDB with the name of your database. If you added additional data sources in your application, you can find the connection strings in the same section of the web.config file, and you can modify these values as appropriate.

796

Chapter 23 ■ Deploying Applications

If you enable authentication in your application, the Publish wizard will have prompted you set up an administrator. You can find the settings that define your application’s administrator in the web.config file, and you can also modify the values manually if necessary. Once you configure these data tasks, you can run setup.exe on your client workstation. This creates a shortcut on the desktop, and the user can use this to start your application.

Installing a Three-Tier Application in IIS When you use the Publish wizard to package for IIS, the wizard produces a single zip file rather than a set of files with an installer, as in the case of a two-tier application. The wizard names your zip file after your application (for example, HelpDesk.zip). This zip file is the package that the IIS installer consumes, and to use it, you will need to install the Web Deploy tool. To install your package, copy the zip file onto your server. Open IIS Manager, use the panel on the left to navigate to your web server, and select the right-click Install option. This opens the Install Application Package wizard. The first page prompts you to enter the path to your zip file. The next page shows the package contents and allows you to review the items that the wizard will install (Figure 23-19). The default items include the SQL script that defines your Intrinsic database, the option to create an IIS application, and the option to install the actual web files. You will need to select all of these for a full installation.

Figure 23-19.  Import Application Package dialog—first page

797

Chapter 23 ■ Deploying Applications

The next page (shown in Figure 23-20) allows you to specify your database connection strings. The first Connection String textbox specifies the connection string that the installer uses to install or update your Intrinsic database. The next textbox allows you to specify the connection that IIS uses at runtime to connect to your Intrinsic database. The wizard provides DatabaseUserName and DatabaseUserPassword textboxes because it expects you to use SQL Server authentication. If you want to use Windows authentication, you need to manually modify your web.config file after the import tool finishes and set up an application pool in IIS, as I described earlier.

Figure 23-20.  Import Application Package dialog—database connection strings Once you complete all the steps in the Import Application Package wizard, your application will be installed. If everything worked correctly, you’ll be able to open a web browser and navigate to the URL where you installed your application. In the case of a desktop application, you’ll see an installation page like the one that’s shown in Figure 23-21. When the user clicks on the Install button, the “Click Once” installer installs your desktop application and creates a desktop icon.

798

Chapter 23 ■ Deploying Applications

Figure 23-21.  Out-of-browser application install page

Three-Tier Manual Deployment Although the wizard provides a rich, graphical way for you to deploy an application, you can just as easily deploy your three-tier application manually rather than creating a zip file and using the Web Deploy tool. If you’re a traditional developer, this technique may suit you well. If you know what you’re doing, it’s quicker than using IIS’s Import Application Package wizard and working through each page one by one. The server-side part of your LightSwitch application is simply an ASP.NET website. Instead of relying on the Import Application Package wizard to create your website, you can create one manually through IIS Manager. You would then use the option in IIS Manager to create an application and configure it to use an application pool that targets the .NET 4 Framework. To publish your application, you still need to use the Publish wizard from within LightSwitch. Once you complete the wizard, you can find your published files in the folder bin\Release\app.publish. You can now simply copy the contents of this folder into the folder for your website. Before you can run your application, you might need to modify the database connection strings in your web.config file so that they refer to the correct data source.

Deploying Data When you were developing your application, you may have added records into your Intrinsic database that you want to deploy. Although the Publish wizard deploys the schema of your database, it won’t deploy the data that you entered at design time. The Publish wizard creates an SQL script that contains the schema of your database, so the easiest way to deploy your data during the installation process is to add SQL INSERT statements to the end of this script file. If you want to retrieve the data that you entered into your design-time database, you can attach your database’s .MDF file using SQL Server Management Studio. Management Studio includes a feature that you can use to script the data in your tables. To use this feature, right-click your database in Object Explorer and start the Script wizard by selecting Tasks ➤ Generate Scripts. When you reach the options page, set the “Script Data” option to true. When the wizard completes, you can copy the SQL INSERT statements that the Script wizard creates and paste the contents to the end of your deploy script.

799

Chapter 23 ■ Deploying Applications

Updating an Application To update an existing application that you have already deployed, you can simply run the Publish wizard again. Each time you use the Publish wizard, LightSwitch automatically increments the version number of your application. If you change the schema of your database, you can select the option in the Publish wizard to “update an existing database.” When you choose this option, the wizard creates a change script that updates only the database objects that have changed. In a three-tier setup, you would install your updated version over your old version. Web clients will automatically run the latest version that’s hosted on your website, and desktop clients will detect that a new version is available and install it.

Troubleshooting Deployment Errors Unfortunately, applications don’t always deploy smoothly, and sometimes it’s very difficult to diagnose the exact cause of a problem. When you deploy a three-tier application, the cause of any problem will often be down to one of three reasons: a problem with IIS’s configuration, a problem with your LightSwitch components, or a problem with database connectivity. Figure 23-22 illustrates some of the common errors that you might encounter.

Figure 23-22.  LightSwitch deployment errors The first error in Figure 23-22 shows an IIS error. If your browser returns an HTTP error code that IIS generates, you have some sort of IIS misconfiguration. This could be a result of permissions or application pool settings. In the case of an IIS error, you can use the HTTP error code to diagnose your problem, and you can also check the Windows Event Log for additional details. Instead of an IIS error, you might encounter what’s known as the “yellow screen of death”—this is a reference to the error page that ASP.NET generates. If this happens, it suggests that you’ve configured IIS and ASP.NET correctly, but have some problem that’s caused by the way that your application is set up in IIS. The error message that ASP.NET returns will hopefully help you diagnose the exact cause of the problem.

800

Chapter 23 ■ Deploying Applications

The second screenshot in Figure 23-22 illustrates a case where the Silverlight client loads successfully, but the application doesn’t load any further. GetAuthenticationInfo is the first server method that your Silverlight client calls, and because of this, it’s common to see error messages that refer to this method. But, deceptively, your problem might have nothing to do with authentication; the best way to diagnose this problem is to trace your application. (I’ll show you how to do this in the next section.) The final type of problem that you might encounter is the dreaded “red X” problem. This is a condition where your application loads successfully, but red crosses appear instead of data. Usually, this indicates a database or network connectivity problem. A classic symptom is that your screen shows the spinning hourglass for 30 seconds before it fails and shows the red X. This 30-second period corresponds with SQL Server’s default connection-timeout period of 30 seconds, and it highly suggests a database connection problem. If you see a red X on your screen, try opening a screen that contains a custom screen query that you’ve written in code. When a LightSwitch control such as DataGrid experiences a data problem, it “swallows” the exception and displays a red X. But when a code query experiences a problem, it’ll raise an unhandled exception, and LightSwitch will open the exception details in a dialog box. The error message that you’ll see includes the exact exception (for example, SQL Exception Timeout Exception), and you can use this to confirm whether or not you have a general database connectivity problem.

Tracing Your Application LightSwitch includes a diagnostic subsystem that integrates with ASP.NET’s tracing functionality. You can use this feature to help diagnose errors, resolve configuration issues, or work out why a query has failed. The trace messages that LightSwitch produces include the server request, the response, and an error description. For performance and security reasons, LightSwitch turns off tracing by default. To turn it on, you need to make some changes to your web.config file; Listing 23-2 shows the sections that you need to modify. Listing 23-2.  Trace settings in web.config

801

Chapter 23 ■ Deploying Applications

Let’s take a closer look at some of these settings: •

Enabled: Set this value to true to turn on tracing.



LocalOnly: When you set this to true, you can view trace messages only when you’re logged on to your web server. If you set this to false, you’ll be able to view the trace data from outside of your server, but note that this is a less secure setting.



Level: This setting allows you to specify the amount of information that LightSwitch logs. For diagnostic purposes, I recommend the verbose setting. This is the setting that retrieves the maximum amount of information.



Sensitive: This setting controls whether or not LightSwitch can include your table data in its trace output. If you set this to true, LightSwitch might write sensitive data (for example, addresses, balances, prices) into the trace log.

The final change that you need to make is to enable ASP.NET’s trace.axd handler. You can find this setting lower down in the file, inside the system.web group. Once you modify your web.config file, you can view your application’s trace by opening a browser and navigating to your website’s trace.axd page (for example, http://MyWebServer/MyApp/trace.axd). When this page opens, you can view a list of trace messages and review additional details by clicking on the View Details link. Figure 23-23 shows an example of the trace output that LightSwitch produces. Notice how the trace registers all calls to the data service. In this example, entries 5 and 6 highlight calls to the data service’s Engineers and Issues methods.

Figure 23-23.  Trace.axd page

802

Chapter 23 ■ Deploying Applications

Deploying to Azure A great feature of LightSwitch is that you can easily deploy applications to Windows Azure—a cloud-based platform. An excellent use-case scenario is to build an HTML client application and then host your application services in Azure. This allows your users to access your application “on the road” using a mobile phone or tablet device that connects to the Internet via a cellular connection. Other advantages of Azure include simplicity, easier maintainability, and scalability. Earlier in this chapter, I showed you how to set up IIS and, hopefully, this hasn’t been too difficult for you. Unfortunately, setting up a web server can be quite tricky, particularly if you have limited knowledge of IIS. For your application to work, you need to install all the necessary components, configure permissions correctly, and make sure that you don’t have firewall or antivirus rules that block your HTTP traffic. If you get this wrong, you can find yourself fighting with errors that can be quite obscure—Azure saves you from all of this. Another benefit of Windows Azure is that it’s easier to maintain your underlying infrastructure. If you’re responsible for managing your own web server (rather than someone else in your company being responsible for it), you’ll appreciate Azure much more. You’ll no longer need to stay at work late every “patch Tuesday” to install Windows Updates, struggle to work out why your server suddenly starts performing sluggishly, or end up being forced to replace a failed hard disk at the most inconvenient moment. Azure also provides scalability. If you need more performance during busy times, you can simply use the web portal to provision more resources (and pay more money, of course). When demand reduces, you can scale back down again. To get started, you need to log in to the Windows Azure website (http://www.microsoft.com/windowsazure/) and sign up for an account. Windows Azure is priced on a “pay as you go” basis, so it’s a good idea to study the pricing details that you can find on the website before you continue. If you’re new to Windows Azure, Microsoft provides a free 30-day trial. This is a great way to test out the service. When you sign up to the service, you need to provide a phone number and credit card number. If you intend only to try the service, remember to cancel your subscription before your trial period expires. Once you create an account, you’ll find it surprisingly easy to publish to Azure. You simply choose the “Azure” option in the Publish wizard and allow the wizard to guide you through the process, step by step. We’ll now examine the publishing process by walking you through the steps that you’ll find in the wizard.

Connecting Visual Studio to Azure To deploy an application to Azure, start the Publish wizard. When you reach the Application Service Configuration page, select the option to host your application in Microsoft Azure. This opens the page that’s shown in Figure 23-24. Use the control at the top of this page to log in to your Azure account.

803

Chapter 23 ■ Deploying Applications

Figure 23-24.  Publish wizard subscription page

Selecting a Service Type You can use the radio buttons in the lower part of the Subscription page to select a service type. There are two options you can choose: a Web App or a Cloud Service. At the time of writing (October 2015), only the “Web App” option is fully supported by the Publish wizard. The Web App service type provides simple hosting and is suitable for most LightSwitch applications. This service provides a hosted IIS environment, and, to give an analogy, this type of service competes with services that web-hosting companies usually offer. Once you create a website, you can increase performance by using the portal to dynamically add additional website instances. Azure will automatically load-balance the web requests between the website instances that you add. The Cloud Service is an example of what’s commonly called Platform as a Service (PaaS). This service type provides you with a virtual machine that you can “remote desktop” onto. The advantage is that you can install your own applications, modify registry settings, and more easily debug your server-side code by logging in to your server. If you select the Cloud Service type, the Publish wizard requires you to install the Microsoft Azure SDK before it continues onto the next page. The Publish wizard prompts you to download version 2.6 through Web PI. This version will fail to install because it is not compatible with Visual Studio 2015 RTM. At this point, you might be tempted to download the latest version of the Azure SDK. This is version 2.7.1 at the time of writing. You should not install version 2.7.1, because it breaks the Publish wizard. If you install this version, Visual Studio produces the error “Could not load file or assembly Microsoft.VisualStudio.Azure. CommonAzureTools.Utilities, version 1.3.0.0” when you start the Publish wizard, and this will prevent you from publishing any LightSwitch application. This is a known problem, and I hope that Microsoft will provide a fix for this soon. Assuming that you choose the “Web App” option, the next page in the wizard prompts you to enter the name of the web app. If you haven’t defined a web app, the page in the wizard includes a hyperlink that takes you directly to Azure Portal, where you can add a service.

804

Chapter 23 ■ Deploying Applications

Creating a Database The next significant step is to define the database that supports your application. Figure 23-25 shows the page in the wizard that prompts you to specify your database connection. Notice how this page includes a link to “Provision a database at the Azure Portal.” This link opens the Azure Portal in a new browser window, and you can navigate to the SQL Databases section of the portal to create a new Azure database.

Figure 23-25.  Set up your database Figure 23-26 shows a screenshot of a database in the Azure portal. There are two useful links on this page. The first is the “View SQL Database connections strings” link. This opens a dialog that you can use to copy an ADO.NET connection string into your clipboard. Once you do this, you can paste the value into the Publish wizard’s “Specify the user connections” textbox. Make sure to amend your connection string to include your password. The connection string that the portal shows does will not include your password.

805

Chapter 23 ■ Deploying Applications

Figure 23-26.  Set up your database For security reasons, SQL Azure includes a built-in firewall that restricts access to your database by IP address. If you want to establish a connection to your SQL Azure database from your development PC (using Management Studio, for example), use the “Set up Windows Azure firewall rules for this IP address” link to add a firewall exception. Returning to the page in the Publish wizard (Figure 23-25), the lower section of the dialog includes a “Publish database schema” checkbox that you can use to create or update your Intrinsic application database. If you specify an SQL Azure database in this section, the publish process will fail. This is because the Publish wizard executes SQL that attempts to place the database into single-user mode through the command: ALTER DATABASE SET SINGLE_USER. SQL Azure does not support this syntax, and the remainder of the database update will fail. Therefore, a more reliable way to publish your Intrinsic database to Azure is to first publish to an interim on-premises, or local, SQL Server database. Once the Publish wizard completes, you can use SQL Server Management Studio to script this database and to restore the contents into your Azure database.

Completing the Publishing Process The remaining steps in the wizard allow you to specify an HTTPS certificate and to sign your XAP file with a digital certificate (in the case of a Silverlight application). Once you complete all the steps in the wizard, you can click the Publish button and complete the deployment of your application to Azure. This section hopefully highlights how simple it is to deploy your applications to Windows Azure. If you want to expose your application over the Internet, Windows Azure is a great choice, but it isn’t the only option. You should not overlook the services that web-hosting companies offer. The web-hosting market is competitive, and there are many companies that can host your LightSwitch application for a cheaper price. You should also consider the security and privacy implications of exposing your application over the Internet. If you expose your application over the Internet, it’s up to you to review the sensitivity of your data and to risk-assess the impact that a data breach could have on your business. With Windows Azure, you should also be aware that because Microsoft is a US company, any data that you store in Azure can be subject to interception by US authorities. You won’t be too shocked by this if you live in the US, but if you live in Europe (for example), you might want to do an Internet search on “US PATRIOT Act” to read more about the impact of choosing to use a US firm for processing and storing your data.

806

Chapter 23 ■ Deploying Applications

Publishing to SharePoint With LightSwitch, you can host you applications in SharePoint 2013 (or above) or Office 365. It can be beneficial to host your application in SharePoint if your organization already uses SharePoint. One advantage is that it enables you to customize your application so that it integrates more closely with your SharePoint system. For example, you can implement authentication using SharePoint identities and permissions, or create list items, create workflows, or add images to SharePoint picture libraries. The SharePoint client object model (CSOM) is the API that allows you to write code that integrates your LightSwitch application with SharePoint. You can find out more about CSOM on the help page: http://go.microsoft.com/fwlink/?LinkId=285361 The quickest way to get started is to create a SharePoint developer site on Office 365. You can find out how to do this by visiting the following web page: http://go.microsoft.com/fwlink/?LinkId=263490. After you prepare your SharePoint or Office 365 website, the first step is to enable the SharePoint feature in your LightSwitch project. To do this, right-click your project and select the “Enable SharePoint” menu item. This opens the dialog that’s shown in Figure 23-27. You can use this to specify the address of your SharePoint site.

Figure 23-27.  Enabling SharePoint When you click the Finish button, LightSwitch adds a new project into your solution, and it also adds references to several supporting assemblies. You can modify your SharePoint address afterward through the properties of your LightSwitch project. When you now debug your application, LightSwitch uses SharePoint to provide authentication, and then it redirects you to an instance of your application it hosts locally in IIS Express. To deploy your application to SharePoint, run the LightSwitch Publish wizard. The key difference is that the Publish wizard provides a page you can use to specify your SharePoint server settings (Figure 23-28). You can complete the deployment of your application by following the remaining pages in the Publish wizard.

807

Chapter 23 ■ Deploying Applications

Figure 23-28.  Configuring your SharePoint settings

Summary In this chapter, I showed you how to deploy your LightSwitch application. It’s possible to create many different types of applications, which results in several distinct deployment combinations. LightSwitch applications depend on application services that you can install on an IIS server, on Azure, or on the client workstation. You can install your application services on the client only if you’re building a desktop application. This deployment scenario is ideal for stand-alone applications or applications that do not have many users. However, there’s a larger deployment overhead involved, because you’ll need to install the application services on each workstation that accesses your application. For HTML client or desktop browser applications, you must host your application services in IIS or Windows Azure. If you choose to host your application in IIS, there are several setup tasks that you need to carry out. First, you need to install the .NET 4.6 Framework. Next, you need to install IIS, and the exact way to do this depends on your server’s operating system. Finally, you need to install the Web Deploy tool; a simple way you can do this is to use the Web Platform Installer (Web PI). Other relevant IIS settings include setting up SSL and adding application pools. SSL makes your application more secure by encrypting the data between your LightSwitch client and server. Application pools improve reliability by isolating the applications that run on your web server. If a web application crashes, it won’t bring down other web applications that run in other application pools. Application pools also allow you to set up your data service to use Windows authentication with your SQL Server. LightSwitch includes a Publish wizard that allows you to deploy your application. This contains a series of screens that guide you step by step through the deployment process. For three-tier IIS deployments, you can choose to either package or publish your application. The difference between publishing and packaging is that publishing deploys an application immediately to your IIS server, whereas packaging produces setup files that you need to manually install afterward. In the case of Silverlight applications, the Publish wizard allows you to digitally sign your XAP file. If you don’t sign your application, Windows shows a dialog when your user installs your application that warns that your application might be dangerous.

808

Chapter 23 ■ Deploying Applications

If you choose to package your application, the Publish wizard produces a deployment zip file. To install a package, you can use IIS’s Install Application Package wizard to install your package. This wizard takes care of setting up your application service’s website and creating the SQL Server database that supports your application. For two-tier desktop applications, the Publish wizard produces a file called Setup.exe, along with supporting database objects and a script that creates your database. To install your application, you need to run the database script against your database server, and run the setup.exe file on the client workstation. To update an existing application, you can simply rerun the wizard. The Publish wizard can analyze your existing database and produce an SQL script that applies the incremental schema changes that you’ve made. The Publish wizard also allows you to deploy your application to Windows Azure. Azure is a cloud service that allows you to publish applications that users can access through the Internet. The service works on a “pay as you go” basis, and the cost depends on the resource and network utilization of your application. To use Azure, you need to set up an account by using the Azure web portal. You can host your application by using either a web app or a cloud service. An Azure web app provides simple hosting, whereas the cloud service provides an environment that supports a “remote desktop” and allows you to install custom software. Finally, you can host your application in SharePoint or Office 365. One of the advantages of hosting your application in SharePoint is that you can integrate your application with lists, libraries, and other SharePoint assets. Sadly, this brings us to the end of the book. I hope that you found it useful; well done for persevering through all the chapters! You’re now capable of building some excellent LightSwitch applications, and I wish you the very best of luck in all of your LightSwitch endeavors.

809

Appendix A

Culture Names In Chapter 2, I showed you how to set the data type of a property to the Money business type. With this business type, you can set the currency code of the property; Table A-1 shows a list of the most popular currency codes. Table A-1.  Currency Symbols

Code

Description

USD

US Dollar

GBP

British Pound

EUR

Euro (European Currency Unit)

AUD

Australian Dollar

CHF

Swiss Franc

JPY

Japanese Yen

NZD

New Zealand Dollar

CAD

Canadian Dollar

When you build an application that supports multiple languages, it’s useful to understand the culture names that you can use. Table A-2 shows you a list of culture names. The culture name is a combination of an ISO 639 two-letter culture code that describes the language and an ISO 3166 two-letter uppercase subculture code that identifies the country or region if necessary. For the name to be valid, the culture portion must be in lowercase and the country/region portion in uppercase. Table A-2.  Culture Names

Code

Description

af

Afrikaans

ar-AE

Arabic (U.A.E.)

ar-BH

Arabic (Bahrain)

ar-DZ

Arabic (Algeria)

ar-EG

Arabic (Egypt) (continued)

811

Appendix A ■ Culture Names

Table A-2. (continued)

Code

Description

ar-IQ

Arabic (Iraq)

ar-JO

Arabic (Jordan)

ar-KW

Arabic (Kuwait)

ar-LB

Arabic (Lebanon)

ar-LY

Arabic (Libya)

ar-MA

Arabic (Morocco)

ar-OM

Arabic (Oman)

ar-QA

Arabic (Qatar)

ar-SA

Arabic (Saudi Arabia)

ar-SY

Arabic (Syria)

ar-TN

Arabic (Tunisia)

ar-YE

Arabic (Yemen)

be

Belarusian

bg

Bulgarian

ca

Catalan

cs

Czech

da

Danish

de

German (Standard)

de-AT

German (Austria)

de-CH

German (Switzerland)

de-LI

German (Liechtenstein)

de-LU

German (Luxembourg)

el

Greek

en

English

en-AU

English (Australia)

en-BZ

English (Belize)

en-CA

English (Canada)

en-GB

English (United Kingdom)

en-IE

English (Ireland)

en-JM

English (Jamaica)

en-NZ

English (New Zealand)

en-TT

English (Trinidad)

en-US

English (United States) (continued)

812

Appendix A ■ Culture Names

Table A-2. (continued)

Code

Description

en-ZA

English (South Africa)

es

Spanish (Spain)

es-AR

Spanish (Argentina)

es-BO

Spanish (Bolivia)

es-CL

Spanish (Chile)

es-CO

Spanish (Colombia)

es-CR

Spanish (Costa Rica)

es-DO

Spanish (Dominican Republic)

es-EC

Spanish (Ecuador)

es-GT

Spanish (Guatemala)

es-HN

Spanish (Honduras)

es-MX

Spanish (Mexico)

es-NI

Spanish (Nicaragua)

es-PA

Spanish (Panama)

es-PE

Spanish (Peru)

es-PR

Spanish (Puerto Rico)

es-PY

Spanish (Paraguay)

es-SV

Spanish (El Salvador)

es-UY

Spanish (Uruguay)

es-VI

Spanish (Venezuela)

et

Estonian

eu

Basque

fa

Farsi

fi

Finnish

fo

Faeroese

fr

French (Standard)

fr-BE

French (Belgium)

fr-CA

French (Canada)

fr-CH

French (Switzerland)

fr-LU

French (Luxembourg)

ga

Irish

gd

Gaelic (Scotland)

he

Hebrew

hi

Hindi (continued)

813

Appendix A ■ Culture Names

Table A-2. (continued)

Code

Description

hr

Croatian

hu

Hungarian

id

Indonesian

is

Icelandic

it

Italian (Standard)

it-CH

Italian (Switzerland)

ja

Japanese

ji

Yiddish

ko

Korean

ko

Korean (Johab)

lt

Lithuanian

lv

Latvian

mk

Macedonian (FYROM)

ms

Malaysian

mt

Maltese

nl

Dutch (Standard)

nl-BE

Dutch (Belgium)

no

Norwegian

pl

Polish

pt

Portuguese (Portugal)

pt-BR

Portuguese (Brazil)

rm

Rhaeto-Romanic

ro

Romanian

ru

Russian

ru-MO

Russian (Republic of Moldova)

sb

Sorbian

sk

Slovak

sl

Slovenian

sq

Albanian

sr

Serbian

sr-Cyrl-CS

Serbian (Cyrillic, Serbia and Montenegro)

sr-Latn-CS

Serbian (Latin, Serbia and Montenegro)

sv

Swedish (continued)

814

Appendix A ■ Culture Names

Table A-2. (continued)

Code

Description

sv-FI

Swedish (Finland)

sx

Sutu

sz

Sami (Lappish)

th

Thai

tn

Tswana

tr

Turkish

ts

Tsonga

uk

Ukrainian

ur

Urdu

ve

Venda

vi

Vietnamese

xh

Xhosa

zh-CN

Chinese (Simplified, PRC)

zh-HK

Chinese (Traditional, Hong Kong SAR)

zh-SG

Chinese (Simplified, Singapore)

zh-TW

Chinese (Traditional, Taiwan)

zu

Zulu

815

Appendix B

Data Type Identifiers When you build LightSwitch extensions, you often need to use string identifiers to define data types. This table contains a list of valid identifiers that you can use.

LightSwitch Data Types :Binary :Boolean :Byte :DateTime :Date :Decimal :Double :Guid :Int16 :Int32 :Int64 :SByte :Single :String :TimeSpan

LightSwitch Extension Data Types Microsoft.LightSwitch.Extensions:EmailAddress Microsoft.LightSwitch.Extensions:Image Microsoft.LightSwitch.Extensions:Money Microsoft.LightSwitch.Extensions:Percent Microsoft.LightSwitch.Extensions:PhoneNumber Microsoft.LightSwitch.Extensions:WebAddress

817

Appendix B ■ Data Type Identifiers

The LightSwitch data types that begin with: and are not preceded with a namespace refer to types that belong to the Microsoft.LightSwitch namespace. In Chapter 19, I showed you how to create a custom value control. To specify the data type that a custom control supports, you would edit its LSML metadata file and specify a data type from those shown in this table. In Chapter 20, I showed you how to create a business type. Business types are based on basic LightSwitch data types. To define the underlying data type, you would edit the LSML metadata file for your business type and specify one of the basic data types from this table.

818

Appendix C

Using Properties in Custom Controls When you create a custom Silverlight control extension, you can bind the attributes of user-interface (UI) elements to the values that a developer enters in the Visual Studio screen designer (Figure C-1).

Figure C-1.  Property values that developers can modify Chapter 19 (Listing 19-7) included a custom control that binds to values from the property sheet. An excerpt of this code is shown in Listing C-1.

819

Appendix C ■ Using Properties in Custom Controls

Listing C-1.  Using property names

The data-binding syntax in this code includes the property names Width, Height, TextAlignment, and VerticalAlignment. You can use these property names in your XAML and .NET code. The purpose of this appendix is to show you a list of property names that you can use in your code. The appearance properties that are shown next are “opt-out” properties. This refers to properties that LightSwitch automatically shows in the property sheet: •

AttachedLabelPosition



HeightSizingMode



WidthSizingMode



MinHeight



MaxHeight



MinWidth



MaxWidth



Height



Width



Rows



Characters



VerticalAlignment



HorizontalAlignment

The other group of property names that you can refer to are “opt-in” properties. By default, these properties don’t show up in Visual Studio’s properties sheet. To make them appear, you need to set the property’s EditorVisibility value to PropertySheet in your custom control’s LSML file, as shown in Listing C-2. Refer to Chapter 19 (Listing 19-23) to see a full example of a custom control’s LSML file.

820

Appendix C ■ Using Properties in Custom Controls

Listing C-2.  Making properties visible in Visual Studio’s properties sheet

The two EditorVisibility values that you can set are the following: •

NotDisplayed



PropertySheet

Here’s a full list of opt-in properties that you can use: •

ShowAsLink



FontStyle



TextAlignment



BrowseOnly



Image

To see a built-in control that implements two of these opt-in properties, take a look at the label control. If you add a label control to a screen and open the properties sheet, you can find options to set the ShowAsLink and FontStyle properties.

821

Appendix D

Custom Screen Template View IDs When you build a custom screen template (like I showed you in Chapter 20), you can call methods from the host-generator object to add content items to your screen. Once you add a content item, you can call the SetContentItemView method to change the control that binds to your content item. In effect, the SetContentItemView method provides the code equivalent of your using the drop-down box that appears next to a content item in the screen designer to select a different control type. Let’s say that you add a local screen property called screenPropertyContentItem and want to change the control type from an autocomplete box (the default control) to a rows layout. Here’s the code that you would use: host.SetContentItemView(screenPropertyContentItem, "Microsoft.LightSwitch:RowsLayout"); "Microsoft.LightSwitch:RowsLayout" is the view ID that identifies the RowsLayout control type. When you build a custom screen template, it’s useful to know what view IDs to use; the table that follows summarizes these IDs.

Desktop Client View IDs Control Type

View ID String

Data Grid

Microsoft.LightSwitch.RichClient:DataGrid

List

Microsoft.LightSwitch.RichClient:List

Command Controls Button

Microsoft.LightSwitch.RichClient:Button

Link

Microsoft.LightSwitch.RichClient:Link

Details Controls Summary

Microsoft.LightSwitch.RichClient:Summary

Modal Window Picker (Details)

Microsoft.LightSwitch.RichClient:ModalWindowPickerDetails

AutoCompleteBox (Details)

Microsoft.LightSwitch.RichClient:DetailsAutoCompleteBox

Value-Picker Controls (*) Modal Window Picker (Value)

Microsoft.LightSwitch.RichClient:ModalWindowPickerValue

AutoCompleteBox (Value)

Microsoft.LightSwitch.RichClient:ValueAutoCompleteBox (continued)

823

Appendix D ■ Custom Screen Template View IDs

Control Type

View ID String

Group Controls Modal Window

Microsoft.LightSwitch.RichClient:ModalWindow

Rows Layout

Microsoft.LightSwitch.RichClient:RowsLayout

Columns Layout

Microsoft.LightSwitch.RichClient:ColumnsLayout

Table Layout

Microsoft.LightSwitch.RichClient:TableLayout

Table Column Layout

Microsoft.LightSwitch.RichClient:TableColumnLayout

Tabs Layout

Microsoft.LightSwitch.RichClient:TabsLayout

DataGridRow

Microsoft.LightSwitch.RichClient:DataGridRow

Picture And Text

Microsoft.LightSwitch.RichClient:PictureAndText

Text And Picture

Microsoft.LightSwitch.RichClient:TextAndPicture

GroupBox

Microsoft.LightSwitch.RichClient:GroupBox

Address Viewer SmartLayout

Microsoft.LightSwitch.Extensions:AddressViewerSmartLayout

Address Editor SmartLayout

Microsoft.LightSwitch.Extensions:AddressEditorSmartLayout

WebLink

Microsoft.LightSwitch.Extensions:WebLink

WebAddress Editor

Microsoft.LightSwitch.Extensions:WebAddressEditor

Value Controls TextBox

Microsoft.LightSwitch.RichClient:TextBox

Label

Microsoft.LightSwitch.RichClient:Label

CheckBox

Microsoft.LightSwitch.RichClient:CheckBox

DateTime Picker

Microsoft.LightSwitch.RichClient:DateTimePicker

DateTime Viewer

Microsoft.LightSwitch.RichClient:DateTimeViewer

Date Picker

Microsoft.LightSwitch.RichClient:DatePicker

Date Viewer

Microsoft.LightSwitch.RichClient:DateViewer

Static Image

Microsoft.LightSwitch.RichClient:StaticImage

Static Label

Microsoft.LightSwitch.RichClient:StaticLabel

Email Address Viewer Control

Microsoft.LightSwitch.Extensions:EmailAddressViewerControl

Email Address Editor Control

Microsoft.LightSwitch.Extensions:EmailAddressEditorControl

Image Viewer Control

Microsoft.LightSwitch.Extensions:ImageViewerControl

Image Editor Control

Microsoft.LightSwitch.Extensions:ImageEditorControl

Money Viewer Control

Microsoft.LightSwitch.Extensions:MoneyViewerControl

Money Editor Control

Microsoft.LightSwitch.Extensions:MoneyEditorControl

Phone Number Viewer Control

Microsoft.LightSwitch.Extensions:PhoneNumberViewerControl

Phone Number Editor Control

Microsoft.LightSwitch.Extensions:PhoneNumberEditorControl

Percent Viewer Control

Microsoft.LightSwitch.Extensions:PercentViewerControl

Percent Editor Control

Microsoft.LightSwitch.Extensions:PercentEditorControl

824

Appendix D ■ Custom Screen Template View IDs

HTML Client View IDs Control Type

View ID String

Tile List

Microsoft.LightSwitch.MobileWeb:TileList

List

Microsoft.LightSwitch.MobileWeb:List

Table

Microsoft.LightSwitch.MobileWeb:Table

Details Controls Summary

Microsoft.LightSwitch.MobileWeb:Summary

Details Picker

Microsoft.LightSwitch.MobileWeb:DetailsModalPicker

Value-Picker Controls (*) Drop-Down

Microsoft.LightSwitch.MobileWeb:ValueDropdown

Group Controls Rows Layout

Microsoft.LightSwitch.MobileWeb:RowsLayout

Columns Layout

Microsoft.LightSwitch.MobileWeb:ColumnsLayout

Value Controls Text

Microsoft.LightSwitch.MobileWeb:Text

Text Area

Microsoft.LightSwitch.MobileWeb:TextArea

Text Box

Microsoft.LightSwitch.MobileWeb:TextBox

Paragraph

Microsoft.LightSwitch.MobileWeb:Paragraph

Flip Switch

Microsoft.LightSwitch.MobileWeb:FlipSwitch

Date Time Picker

Microsoft.LightSwitch.MobileWeb:DateTimePicker

Date Picker

Microsoft.LightSwitch.MobileWeb:DatePicker

Email Address Viewer

Microsoft.LightSwitch.MobileWeb:EmailAddressViewer

Email Address Editor

Microsoft.LightSwitch.MobileWeb:EmailAddressEditor

Image

Microsoft.LightSwitch.MobileWeb:Image

Money Viewer

Microsoft.LightSwitch.MobileWeb:MoneyViewer

Money Editor

Microsoft.LightSwitch.MobileWeb:MoneyEditor

Phone Number Viewer

Microsoft.LightSwitch.MobileWeb:PhoneNumberViewer

Phone Number Editor

Microsoft.LightSwitch.MobileWeb:PhoneNumberEditor

Percent Viewer

Microsoft.LightSwitch.MobileWeb:PercentViewer

Percent Editor

Microsoft.LightSwitch.MobileWeb:PercentEditor

* LightSwitch uses value picker controls to display the choice list items that you define through the table property editor.

825

Appendix E

Data Schemas Throughout this book, I have referred to tables from the Help Desk sample application. In Chapter 2, I described the main tables and relationships in the application. This appendix summarizes the remaining tables that belong in this application.

Help Desk Tables Here are the tables found in the Intrinsic database, organized in alphabetical order.

827

Appendix E ■ Data Schemas

828

Appendix E ■ Data Schemas

829

Appendix E ■ Data Schemas

830

Appendix E ■ Data Schemas

831

Appendix E ■ Data Schemas

832

Appendix E ■ Data Schemas

833

Appendix E ■ Data Schemas

834

Appendix E ■ Data Schemas

835

Appendix E ■ Data Schemas

836

Appendix E ■ Data Schemas

837

Appendix E ■ Data Schemas

External Tables In Chapter 6, I showed you how to insert records into an external SQL Server database. Here’s the schema and create script (Listing E-1) for the AuditDetail table. Listing E-1.  SQL create script for AuditDetail table

Database Diagram The following diagram shows the tables and relationships in the Intrinsic database after you deploy your application.

838

Appendix E ■ Data Schemas

839

Index

„„         A Access control methods, 260 AddNew method, 300 Aggregate counts/sums/averages desktop application, 381 Timesheet collection, 380 timesheet table, 379 TotalMinutes and drag, 379–380 AppendSemiColonConverter, 631 AppOption method, 364 AppOptionProperty method, 367 AppOptionsEdit method, 364 ApressControls.dll assembly, 599–600 Architecture, 4 data tier, 5 logic tier, 5 data retrieval, 5 data saving, 6 presentation tier, 6 HTML client, 6 LightSwitch screens, 8 Silverlight client, 7 ASP.ET, eeb page, 477 ASP.NET AddTo method, 477 chart control, 492 LightSwitch data, 493 LINQ, 495 pie chart, 494 screen designer view, 492 PriorityChart.aspx, 492 grid data FindControl method, 492 IssuesByEngineer.aspx, 486 LightSwitch data, 488 modification, 490 nested view, 490 page layout, 487 RowDataBound event, 491 system tray icon, 490

LightSwitch database, 475 load method, 478 reading data, 478, 480 SaveChanges method, 477 security and deployment, 495 ViewIssues.aspx, 478 web.config file, 477 web form, 475, 485 Authorized users, 751 administrator application, 753 Bypass validation, 774 design-time view, 764 drop-down list control, 764 login screen, 768 CanRun method, 770 conditions, 769 HTML applications, 770 mangers and non-managers, 768 permissions access control, 753 debug mode, 755 roles and users, 751 screen control, 772 roles screen, 754 row-level access, restrict, 771 security client objects. Client objects, security server objects. Server objects, security SecurityData object, 767 users screen, 754

„„         B BeginInvoke method, 284 Built-in search Exists/in type, 313 filter child items, 311 date elements, 315

841

■ index

Built-in search (cont.) LINQ, 308 engIssue variable, 309 invalid query, 326 lambda expressions, 310 Method Syntax, 309 queryDescriptor parameter, 326 Query Syntax, 309 runtime error, 326 not exists/not in, 314 overview, 305 search query, 306 search screen html file, 328 query parameters, 308 runtime view, 327 screen designer, 307 templates, 308 string-matching, 318 case sensitivity, 323 multiple words, 321 non-concurrent words, 318 phonetic searching, 323 top N records, 317 Business type extension, 656 AttributeClass, 659 AttributeProperty, 659 controls, 657 creation, 656 DurationMins property, 674 DurationType, 656 MaxIntegerValidation class, 660, 663 MaxIntegerValidationFactory class, 660 overview, 656 property editor window, 665 attributes, 673 data-binding code, 667 factory class, 673 MaxIntegerEditor class, 669 popup window, 667 UIEditor, 669 ValueProperty, 669 WPF user control, 668 slider control, 674 validation rule, 657 Business types, 23 email addresses, 23 monetary values, 23 people data, 26 phone numbers, 25 web addresses and percentage values, 26

842

„„         C CanRun method, 260 Cascading Style Sheets (CSS), 229 Checkbox controls (read-only), 278–279 Choice list creation, 27 vs. related tables, 28 Client object model (CSOM), 807 Client objects, security, 761 HTML applications, 763 restrict users CanExecute method, 762 CanRun method, 761 execute method, 761 Client-side data-access code AddNew method, 135 DataWorkspace object, 135 delete records, 140 IssueStatus, 133 read records, 142 SaveChanges method, 135 SystemSetup screen, 134 update records, 136 code implementation, 138 get method, 140 HTML client layout, 138–139 IssueStatus property, 136 SaveChanges method, 139 screen designs, 138 SystemSetup screen, 136 CloseModalWindow method, 300 Collection Methods, 260 ComboBoxQueryProperty, 620 ComboDisplayItemProperty, 620 Computed properties, 37 calculating dates with, 38 returning images with, 40 sorting and filtering by, 41 summarizing child records with, 39 Concurrency, 160 data conflict screen, 160 auto-generated, 160 error message, 161 HTML client, 161 resolve conflicts, 162 ConfigurationManager namespace, 453 ConnectionStrings section, 453 Control extensions command extension button control code, 650 custom button, 652

■ Index

LSML file, 651 .NET code, 651 overview, 649 custom control types, 598–599 custom property editors convertion, 631 EntityPropertyDropdownEditor class, 637 design project, 629 GetEditorTemplate method, 639 list of, 640 .NET code, 631 properties sheet, 629 runtime designer, 640–641, 645 textbox, 628 UIEditorId attribute, 639 value-converter code, 632–633 Visual Studio, 628–629 WPF editor control, 630 deployment duration editor control, 610 product/installation attributes, 611 VSIX project, 610 detail control (ComboBox) combo box control, 612 entity summary property, 620 metadata, 612–613, 620 overview, 611–612 group control code, 647 label visibility LSML file, 648 toggle layout control, 648 LightSwitch (see LightSwitch extensions) overview, 593 runtime designer overview, 640 silverlight control, 641 SilverlightEntityProperty Dropdown code, 642 SilverlightEntityProperty DropdownEditor class, 642, 645 textblock, 642 steps, 645 subsequent tasks, 599 textblock control, 646 toggle control, 646 value controls control icon, 603 data types, 601 duration editor control, 600 FindControl method, 601 function, 600 height, size and property, 609 optimization, 603–604, 609 steps, 599 XAML markup, 600

CreateEmail method, 588 CreateIssue.aspx method, 474 CreateItem method, 588 CreateObject method, 588 Culture names code and description, 811–815 currency symbols, 811 Custom controls, 407, 432 combo box, 412 data configuration, 413 design screen, 412 data-binding, 410 binding mode, 411 binding path, 410 dependency property, 410 values, 411 design view, 437 EditorVisibility values, 821 opt-in properties, 821 password box, 408 screen designer, 408 system.windows.controls node, 409 property names, 819–820 property sheet, 820 property values, 819 save control, 433 screen method, 434 Silverlight Control, 419 dependency property (see Dependency property) value conversion, 414 code implementation, 416 data binding, 418 office table, 415 screen layout, 416 in Visual Studio’s property sheet, 820 Custom screen template, 823 autocomplete box, 823 desktop client, view IDs, 823 HTML client, view IDs, 825

„„         D Data-access code API, 129 client-side. Client-side data-access code execution queries, 144 Intellisense, 130 nullable data type, 131 Solution Explorer, 130 using promise pattern, 132 audit status changes, 149 discard changes, 151 review multiple changes, 153 Save pipeline, 146

843

■ index

Data-access code (cont.) phases, 147 refresh method, 148 writing codes, 148 Data controls, 58 Boolean values, 60 date picker control, 60 details picker control, 64 email address editor control, 61 lists of records, 61 showing/editing string values, 58 web viewer control, 61 Data-grid optimization, 600 Data-retrieval process, 113 Data schemas database diagram, 838 external tables, 838 HelpDesk tables, 827 Data services, 5 Data-source extension, 724 domain service class, 727 entity class, 724 WCF RIA Service, 732 Data storage, 15 business types, 23 email addresses, 23 monetary values, 23 people data, 26 phone numbers, 25 web addresses and percentage values, 26 entities and properties, 16 fields (properties) creation, 18 binary data, 21 data loss, 22 dates, 21 formatting numeric fields, 19 images, 21 numbers (double and decimal types), 19 numbers (integer types), 19 textual data, 18 unique values, 22 tables (entities) creation, 16 Data summarization, 379 aggregate counts/sums/averages desktop application, 381 Timesheet collection, 380 timesheet table, 379 TotalMinutes and drag, 379–380 EntityCollection, 384 merging data, 383–384 querying data collections, 382–383 Data validation, 167

844

accessing validation results, 187 client-side, 168–169 errors, 169 MVVM appliccation, 169 .NET properties, 169 custom property validation, 171 rules and warnings, 172 custom validation, 174 AddPropertyResult method, 174 child collections, 179 comparsion, 175 EntityValidationResultsBuilder method, 174 Regular expressions, 177 Social Security Number field, 176 deletion process, 192 IssueResponse table, 192 SaveError method, 196 validate method, 195 duplicate references, 192 errors, 168 HTML client validation, 181 predefined validation data-length, 171 field level properties, 170 ranges, 171 required field, 171 screen validation, 186 server-side, 168 SQL Server database, 188 unique index, 188 unique records, 189 workflow, 167 Date picker control, 60 DependencyObject class, 283 Dependency property benefit, 420 data context, 427 duration control, 429 DurationProperty, 426 dynamic value resolution, 419 PropertyMetadata object, 427 time duration, 420 web browser control, 429 Deployment process data, 799 overview, 779 publish/package, 781 Publish wizard application type, 782–783 data connections page, 784–785 digital signature/certificate page, 787–788 prerequisites page, 786 security page, 787 services, 783–784

■ Index

SharePoint 2013 client object model (CSOM), 807 configuration, 807–808 enable menu item, 807 Office 365, 807 SQL Server, 782 steps, 780 three-tier application, 797–799 topology, 780 troubleshooting errors HTTP error code, 800 LightSwitch, 800 red X problem, 801 tracing application, 801–802 two-tier desktop application database connection string, 796 SQL database, 795–796 update, 800 web server application pools, 792–793 .NET 4.6 Framework, 789 secure sockets layer, 795 tasks of, 789 web deploy tool, 791 Windows 7, 791 Windows authentication, 794 Windows Server 2012/2008, 789–790 Windows Azure cloud-based platform, 803 database, 805–806 infrastructure, 803 publishing process, 806 service type, 804 Visual Studio, 803–804 workstations, 781 description attribute, 453 Desktop application, 73 auto-complete box control, 86 benefits, 74 client application creation, 75 control appearances, 88 font styles, 91 label position dialog, 90 sizing options, 89 data entry screens, 77 data grid control, 94 data list control, 94 details screen, 102 EngineerIssues Screen, 104 project size, 109 runtime designer, 108 search screen, 103 target screen, 105 download and save files, 347

editable grid template, 95 configuration, 96 header buttons, 98 Filter Mode property, 86 lists and details screen, 100 modal window picker control, 87 opening files limitation, 349 OpenFileFromDatabase, 350 registered application, 349 properties pane, 106 read-only controls, 92 related data items, 93 screen designer, 78 data controls, 82 data-item containers, 84 group controls, 80 properties, 80 text box control, 84 screen navigation tab, 107 Screen templates, 76 search screen, 101 sending email, 580 screen code, 581 service reference, 581 web.config file, 584 static text and images, 88 uploading files, 343, 346 Desktop applications access grid and list values, 264 add/edit screen, 295–296 controls Findcontrol method, 275–277 handling Silverlight control events, 281, 283 underlying Silverlight control, 279–280 custom text and information access screen collection, 264 database, 262 InitializeDataWorkspace method, 263 IssuesOverdueLabel, 262 sort sequence and number, 262–263 string property, 262 data changes LostFocus method, 288 PropertyChanged method, 288, 290, 294 data-grid dialogs, 297–298, 300 default screen values, 265 engineer dashboard screen, 261 LightSwitch screens access control methods, 260 Closing event, 260 code adding, 259 collection methods, 260 InitializeDataWorkspace method, 260

845

■ index

Desktop applications (cont.) Saving method, 259 screen property methods, 261 screen template type, 260 MessageBox and InputBox alerts, 274–275 modal window, 298 navigation screens buttons/links, 267–269 engineer dashboard screen, 267 passing arguments, 271 refresh screens, 271 unbound auto-complete box, 270 new data screen template, 294–295 screen title (in code), 264–265 tasks, 259 threading syntax. Threads visual collections, 264 Detail control (ComboBox) combo box control, 612 entity summary property CustomEditorHelper class, 621 helper class, 621 overview, 620 SetContentDataBinding method, 626 metadata combo box code file, 615 dependency properties, 620 distinct sections, 620 LSML, 612 XAML code, 614 overview, 611–612 DiscardChanges method, 300 DisplayModeControlTemplate file, 608 Drill-through reports, 503 DurationEditor.lsml file, 601 DurationViewer.xaml files, 610

„„         E Email address editor control, 61 EmptyStringToSummaryConverter, 631 Entities and properties, 16 EntityCollection method, 384 Entity sets, 5 Excel XLS format, 539 code inmplementation, 541 final spreadsheet, 540 late binding, 543 layout, 540 printer documents, 544 ExecuteScalar method, 456 External data sources authentication credentials, 467 Azure marketplace, 466 connection, 468–469 data-source options, 469

846

determining connection, 466–467 OData, 465 third-party data sources, 466 Travel Advisory Service, 466

„„         F Files conversions, 353 desktop application download and save files, 347 opening files, 349–350 uploading files, 343, 346 file-storage capabilities, 329 HTML client applications. HTML client applications size validation, 352 table structure, 329–330 FileUpload control document upload control, 338 IssueDocument table, 337 JavaScript code, 338 render method, 335 uploading files, 332 FindControl method, 275, 290, 410, 492 checkbox controls (read-only), 278–279 data-grid dialogs, 301 Focus method, 276 IContentItemProxy methods, 275 show and hide controls, 276–277 FirstOrDefault method, 367, 479 Focus method, 276

„„         G GetAllEntityPropertiesConverter, 631 getCurrentPosition method, 374, 376 GetEditorTemplate method, 639 GetLocation method, 373 GetObject method, 588 GetSummaryProperty method, 628

„„         H HelpDeskDataService.dll file, 461 HelpDeskPortal method, 473 HTML application design, 43 Common Screen Template, 45 data controls, 58 Boolean values, 60 date picker control, 60 details picker control, 64 email address editor control, 61 lists of records, 61 showing/editing string values, 58 web viewer control, 61

■ Index

navigation structure, 67 adding navigation buttons, 70 changing button icons, 70 configuring navigation menu, 68 multiple screen navigation, 69 setting home screen, 67 positioning controls, 64 running application, 49 screen creation, 43 screen designer tabs, 55 toolbar, 55 top-level screen layout, 53 screen layout with group controls, 56 setting screen properties, 66 HTML client, 6 HTML client application bespoke customization, 231 button icons, 234 colors, 232 CSS rule, 234 developer tools, 236 fonts, 232 image strip, 235 jQuery syntax, 233 label data, 232 postRender method, 232 prols-settings-icon, 236 row colors, 240 splash screen image, 231 tile list controls, 241 conditional formatting, 243 data tables, 243 title list control, 245 CSS files, 229 content folder, 229 graphical designer, 230 ThemeRoller, 230 custom control, 222, 342 apperance, 225 browse screen, 223 data binding, 222 HTML editor, 226 navigation properties, 225 render method, 224 data-binding methods, 217 data changes, running code, 221 format dates, 217 format numbers, 219 design time view, 578–579 file download code, 340 final screen, 343 generic handler, 336 hyperlink, 342 screen designer, 223

popups, 214 CancelPopup methods, 216 DoDelete methods, 216 Issue screen, 216 screen designer, 215 user confirmation, 214 server application context API, 339 screenshot, 578 SendEmail handler page, 578 uploading files approaches, 330 downloading files, 338–339 FileUpload control, 332–333, 337 file-upload technique, 330–331 mobile device cameras, 343 non-HTML5 browsers, 335–336 non technique, 331–332 user-customization CSS file, 248 HTML screen template extension, 719 AddContentItem method, 723 code implementation, 721 ExpandContentItem method, 723 LSML view, 723 popup control, 723 screen design, 720 steps, 719

„„         I IBindablePropertyEntry interface, 629 IBindablePropertyEntry object, 631 IContentItemProxy object, 279 IContentVisual interface, 603 IDataServiceQueryables method, 383 idempotent operation, 572 Identifiers data types, 817 extension data types, 817 InitializeDataWorkspace method, 263, 279, 282 InsertEngineerData method, 456 Internet Information Services (IIS), 779 application pools, 792–793 .NET Framework 4.6, 789 web deploy tool, 791–792 Windows 7, 791 Windows 2012/2008 roles wizard, 790 server role, 789 Internet Service Provider (ISP), 562 Invoke method, 285 InvokeScript method, 515 IssueId method, 296 IssueProperty method, 296 IssuesOverdueLabel method, 262, 279

847

■ index

„„         J, K JavaScript API, 203 objects, 204 contentItems, 204, 207 dataWorkspace, 204 myapp, 204–205 screen, 204, 206 screen methods, 204 screens ClosureDetails, 210 default values, 207 hide controls, 209 title setting, 210

„„         L LightSwitch application building, 9 architecture. Architecture choice list creation, 27 related tables, 28 computed properties, 37 calculating dates with computed properties, 38 returning images with, 40 sorting and filtering by, 41 summarizing child records with, 39 existing data, 32 deletion of data source, 37 relationships between data sources, 37 SharePoint data, 36 existing database, 34 missing tables, 35 refreshing data sources, 35 unsupported data types, 36 history of, 3 relationships deletion of child records, 32 many-to-many relationships, 31 one-to-many-type relationships, 29 self-referencing relationships, 31 in SQL Server, 30 SQL Server data types, 26 summary properties, 37 LightSwitch application, threads, 284 LightSwitch data, 470 Excel connection, 472 .NET 3.5, 473, 478, 480 OData endpoint URLs, 470 platforms and clients, 480–481 query operators, 471 raw OData feed, 471

848

securing feeds, 472 service endpoints, 470 LightSwitch extensions enabling extensions, 595 error message, 594 extensibility toolkit library project, 597 LSPKG project, 598 web pages, 597 manifest file, 594 many-to-many control checkbox list, 596 excel importer, 597 filter control, 597 runtime, 596 steps, 596 updates dialog, 595 VSIX file extension, 593 web page, 593 LightSwitch project creation, 10 key and editable attribute, 447 domain service class, 448 engineer screen, 444–445 entity class creation, 445 required attribute, 448 process of, 444 project creation, 445 setting-up application properties, 12 StringLength attribute, 448 LightSwitch Shell, 7 Linking reports approaches, 507 desktop applications browser window, 507–508 design-time view, 510 details screen template, 512 EngineersManagerGrid screen, 509 LightSwitch screen, 509, 511–512 list/grid control, 511 printing reports, 515 web browser control, 510 HTML client applications design view, 516 hyperlink, 517–518 iframe, 516 pie chart, 517 loaded method, 261 load method, 478 Localization, 387 date formats, 389 desktop application, 401 menu items, 402 .NET code, 403 screen title, 401

■ Index

HTML client application, 398 date and numeric values, 401 JavaScript code, 400 menu and window title, 399 resource files, 399 screen title, 399 .NET server messages, translation, 393 desktop application, 393 HTML client application, 396 validation error, 395 overview, 387 pluralization, 389 server object, 389 supported languages, 388 table translation, 390 desktop applications, 391 HTML client applications, 391 substitution technique, 391 testing, 392 top-aligned labels, 389 Location-based applications, 373 Longitude and latitude measurements, 375 LostFocus method, 288

„„         M MailMessage object, 566 Many-to-many relationships, 31 Microsoft Outlook GetObject method, 588 Outlook message, 585 screen code, 589 Send Email button creation, 590 Microsoft reporting services deployment report designer, 503 import method, 504 interface, 505 properties, 504 property window, 504 designer components preview versions, 496 server-based installation, 496 SSDT-BI, 497 Visual Studio 2015 setup, 497 report designer datasets, 501 design and preview modes, 501 drill-through reports, 503 embedded code, 502 .NET assembly, 502 property values, 503

table and list controls, 502 toolbox pane, 500 reports creation aggregation, 499–500 development database, 498 RDL, 498 SQL query, 499 SQL Server, 496 Model-centric architecture, 8 Model-View-ViewModel (MVVM), 10 msls.promiseOperation method, 580 Multi-record selection technique ASHX handler code, 357, 359 checkbox and description, 355 custom control, 354 JavaScript helper files, 355 multiple records, 353–354 screen button code, 356 server-side method, 359 Multi-threaded applications, 283

„„         N name and description, 704 Navigation screens buttons/links adding button, 269 data grid command, 269 layout screen, 268 passing arguments AssignedEngineer property, 272 open screen, 273 parameter values (in code), 272 screen parameters definition, 271 refresh screens, 271 unbound auto-complete box, 270 Nesting data-selection controls, 368 detail picker control, 372 engineer and department tables, 368 GPS locations getCurrentPosition method, 374 GetLocation, 373 longitude and latitude measurements, 375 user determination, 374 integration (mapping system), 376 default.htm file, 376 department table, 376 Google map, 377 runtime application, 377–378 screen designer view, 376 IssuesByEngineer and UsersByDepartment queries, 369–370 query parameter binding, 372

849

■ index

Nesting data-selection controls (cont.) screen designer view, 371–372 screen-design steps, 370 .NET 3.5 ASP.NET, 474 read data ASP.NET, 478, 480 service reference, 474 WCF, 473 Webform, 475 web page, 477 .NET 4.6 Framework, 789 Non-HTML5 browsers, 335–336

„„         O OData (Open Data Protocol) external data sources, 465–466, 468–469 LightSwitch data. LightSwitch data SAP data, 465 sharing data, 465 Office documents, 521 COM automation, 539 Excel XLS format, 539 late binding, 543 printer documents, 543 COM client automation, 521 mail merge, 544 Build Action property, 553 code implementation, 546 destination, 552 My Documents folder, 553 template-distribution techniques, 553 wordMailMerge object, 551 word template, 544 OpenXML SDK, 521 OpenXML SDK. OpenXML SDK PDF documents, 555 code implementation, 555 silverPDF draw methods, 557 One-to-many-type relationships, 29 OpenModalWindow method, 300 OpenXML SDK command pattern, 523 desktop client applications, 535 HTML client application, 533 installation, 522 overview, 522 productivity tool, 538 word document bookmarks, 524 code implementation, 527 locate tables, 526 templates, 524

850

„„         P Printing reports, 515 ProcessRequest method, 339 PropertyChanged method data changes, 288 details screen, 291, 294 new data screen, 288 SecurityVetted method, 290 Publishing vs. packaging application, 781 Publish wizard application type, 782–783 data connections page output, 784–785 packaging output, 785 digital signature/certificate page certificate server, 788 warning dialog, 787 Intrinsic database, 784 prerequisites page, 786 security page, 787 services, 783–784

„„         Q Queries, 113 data-retrieval process, 113 default queries, 115 filtering controls, 124 filters, 117 comparison property, 119 drop-down menu, 120 global values, 120 literal values, 118 properties, 116 on screens, 126 query pipeline Executed method, 114 ExecuteFailed method, 114 flow chart, 114 PreProcessQuery method, 114 screen modification, 121 sorting, 121 desktop applications, 122 user-setting files, 123 user-defined query, 116

„„         R Related tables, vs. choice list, 28 Relationships deletion of child records, 32 many-to-many relationships, 31 one-to-many-type relationships, 29

■ Index

self-referencing relationships, 31 in SQL Server, 30 Report Definition Language Client-side (RDLC), 505 Reporting Definition Language (RDL), 498 Reports ASP.NET chart control, 492, 495 grid data, 486–487, 490 grids, 490 security and deployment, 495 web form, 485 linking reports browser window, 507, 509 HTML client application, 516–518 LightSwitch screens, 509, 511 printing reports, 515 Microsoft. Microsoft reporting services overview, 485 viewer control convertion, 505 data-binding process, 506 RDLC files, 505 SqlDataSource, 506 web page, 506 Representational State Transfer (REST), 570 ResponseFormat property, 573 ResponseText control, 282 Rich Internet Application (RIA) service consume, 461 dialog appears, 461 entities, 462 history of, 443 LightSwitch project, 444 overview, 443 retrieving data, 448, 453 update and insert database, 453, 456 web.config file, 453 RootControl method, 609

„„         S SaveChanges method, 359, 367 Screen navigation buttons/links comment and link creation, 267 engineer dashboard screen, 267 Screen property methods, 261 Screens, 211 custom HTML, 213 custom text, 211 data item dialog, 212 text value, 212 Screen template extension code implemetation, 716 data-source type, 712

designs, 715 DisplayName property, 711 host generation methods, 719 overview, 708 property settings, 709 requirements, 712 SupportsChildCollections property, 711 Secure Sockets Layer (SSL), 795 SecurityVetted method, 290 Self-joined data assign and deassign subordinates, 362 assignment and de-assignment, 361 DeassignSubordinate code, 362 default subordinate data grid, 360 engineer table, 360 refresh method, 363 screen designer, 361 screen design (HTML client), 361–362 subordinate allocation grid, 363 subordinate collection, 363 un-assign data, 361 Self-referencing relationships, 31 Sending email, 561 desktop application, 580 screen code, 581 service reference, 581 web.config file, 584 HTML client application, 578–579 LightSwitch clients GET and POST method, 572 idempotent operation, 572 implementation, 573 interface file, 571 REST-based web services, 570 SMTP mail messages, 570 SOAP, 570 WCF web service, 570 web browser, 577 web.config file, 573 web.config file, 575, 577 Microsoft Outlook GetObject method, 588 Outlook message, 585 screen code, 589 send email button creation, 590 notifications configuration-save credentials, 562 helper class, 567 MailMessage object properties, 566 reusable email class, 563, 567 SMTP service, 562 Updating method, 567, 569 overview, 561 SendMail method, 569 SendMailREST method, 580

851

■ index

SendMailREST and SendMailSOAP methods, 575 Server objects, security access control entity-set, 755 table, 755 query-level permissions, 760 restrict users edit data, 756 Intellisense options, 757 IsReadOnly method, 759 read data, 757 save data, 758 Service-behavior configuration, 577 SetBinding method, 279 SetContentDataBinding method, 628 SharePoint 2013 client object model (CSOM), 807 configuration, 807–808 enable menu item, 807 Office 365, 807 Shell extension application logo, 681 ApressShell.xaml.vb or ApressShell.xaml.cs, 681 command bar section, 680 DataTemplate section, 681 execution commands, 701 final shell, 705 INavigationScreen, 700 IServiceProxy object, 702 navigation process, 702 overview, 675 project creation, 675 proposed layout, 676 Screen-Handling Code, 701 ScreenWrapper class, 682 Change Notification, 688 code implementation, 682 IsDirty Property, 688 ShellHelper code, 689 underlying Properties, 688 ValidationResults Property, 688 StackPanel, 679 value converters, 692 CurrentUserConverter, 693 ScreenHasErrorsConverter, 692 ScreenResultsConverter, 692 WorkspaceDirtyConverter, 692 XAML code, 693 Value Converters, 682 view models, 680 showMessageBox method, 580 ShowMessageBox and ShowInputBox method, 275 Silverlight client, 7 applying themes, 8 LightSwitch Shell, 7

852

Silverlight control characters, 283 ControlAvailable, 280 handling events, 281 IContentItemProxy object, 279 InitializeDataWorkspace method, 279 SetBinding method, 279 textbox control, 281–282 underlying controls, 279 Simple Object Access Protocol (SOAP), 570 Single-row tables (screen) application options screen, 368 AppOption table, 364 AppOptionProperty, 367 edit screen, 365 record creation, 366–367 steps, 364, 366 SmtpMailHelper class, 566 .sql, 796 SqlCommand object, 453 SqlConnection object, 453 SQL Server authentication, 794 data types and LightSwitch, 26 deploying application, 782 relationships in, 30 SQL Server Data Tools (SSDT), 496 SQL Server reporting services, 496 State handling, 600 StatesControl element, 600 Summary properties, 37

„„         T Tables (entities) creation, 16 TextBoxKeyUp method, 282 Theme extension, 706 colors, 707 fonts, 706 Threads BeginInvoke, 284 code execution, 285 Dispatcher object, 284 DualDispatcherObject, 287 FindControl method, 286 Invoke method, 285 IssueProperty, 287 LightSwitch application, 284 multiple tasks, 283 PropertyChanged event, 287 rules, 283 threading code, 286 UI elements, 283 UI threads, 283 worker rule, 283

■ Index

Three-tier application import application database connection strings, 798 dialog—first page, 797 out-of-browser application, 799 manual deployment, 799 Three-tier architecture. Architecture Transactional system, 156 atomicity, 156 SaveChanges operation, 156 Save pipeline, 157 AuditDetail table, 157 code implementation, 158 execution phase, 160 Troubleshooting deployment errors HTTP error code, 800 LightSwitch, 800 red X problem, 801 tracing application, 801–802 Two-tier desktop application, 796 database connection string, 796 SQL database, 795

„„         U UI customization, 250 Browse Issues screen, 257 CSS file, 253 flat-style buttons, 257 header section, 250–251 JavaScript code, 253 runtime file, 251 taskHeaderTemplate sectio, 256 UpdateEngineerData method, 456 Updating method, 567, 569 User authentication, 737 aspnet_Roles table, 741 aspnet_Users table, 741 default option, 738 forms authentication, 738, 740 logout application, 746 membership provider, 742 password complexity rules, 742 encryption settings, 743

share forms, ASP.NET, 744 ConnectionStrings element, 744 machine key settings, 745 name settings, 745 web.config file, 744 windows authentication, 737, 739 UserControl.Resources tag, 601

„„         V Value-added features, 570 Value controls control icon, 603 data types, 601 duration editor control, 600 FindControl method, 601 function, 600 height, size and property, 609 optimization display-mode template, 609 duration control, 603–604 DurationViewer.xaml, 604 read-only display-mode template, 607 string representation, 606 steps, 599 XAML markup, 600

„„         W, X, Y, Z WCF RIA Service, 732 web.config file, 453 Web deploy tool, 791–792 Web viewer control, 61 Windows 7, 791 Windows 2012/2008 roles wizard, 790 server role, 789 Windows authentication, 794–795 Windows Azure cloud-based platform, 803 database, 805–806 infrastructure, 803 publishing process, 806 service type, 804 Visual Studio, 803–804 Windows Communication Foundation (WCF), 473

853