If you've ever had to replace your smart phone with a different make and model, it can be a real struggle getting to grips with something that you're unfamiliar with. For example, installing apps might be simple, but understanding how everything works beneath the surface could be quite obscure. Likewise, you might also choose to switch off Wi-Fi (or some other operation) by navigating through several levels of menus, because a more direct route isn't apparent.
In many ways, learning LightSwitch is a similar experience. Behind the point and click facade of the GUI, what actually happens behind the scenes? Are there easier ways to perform tasks that you can already achieve?
In this chapter, we'll unwrap LightSwitch and expose the inner workings of the product. You'll learn about the constituent projects that make up a LightSwitch solution and find out more about the role that SQL Server Express plays.
The default view that's shown to you when working with LightSwitch is called Logical view. This basic view organizes a project into various folders such as Data Sources
, Entities
, and Screens
. The Logical view enables you to add and edit items such as screens, queries, and data sources.
In addition to the Logical view, there is a second view called the File view. Knowing how to switch to this view is important if you want to undertake any serious LightSwitch development. This view allows you to see the various parts that make up a LightSwitch solution and enables you to work on individual projects. In addition, it allows you to add references to external DLLs in individual projects.
To switch to File view, use the drop-down in Solution Explorer and select the File View option, as shown in Figure 2-1.
After switching to File view, you'll see a project listing. The toolbar within Solution Explorer includes a Show All Files button, as illustrated in Figure 2-2. Clicking this button displays all files that exist on the file system and reveals two additional projects, which are the ClientGenerated
and ServerGenerated
projects. With this option turned off, these projects are hidden along with a few other files, which include default.htm
and Silverlight.js
files.
Figure 2-2 illustrates the projects that make up a LightSwitch solution. These include the following:
Client
ClientGenerated
Common
Server
ServerGenerated
In the following section, you'll discover what these projects actually do.
If you examine the root folder of a LightSwitch project in Windows Explorer, you'll find subfolders that correspond to the projects that have been mentioned. You'll also find several other files that are needed to support your LightSwitch application.
A _pvt_extensions
folder is created if any custom extensions are used in your project. This folder contains a subfolder for each extension that's used. For example, a LightSwitchFilter
folder will be created if the LightSwitch filter extension is used in your project.
The Silverlight.js
file is a JavaScript file that is automatically added to all Silverlight web applications. It contains various helper functions that support the use of Silverlight within the browser.
Default.htm
is the web page that's used for hosting the Silverlight LightSwitch client. This file is used when an application is set to run as a web application. It's also used to load an out-of-browser (desktop) application. After the out-of-browser application is installed, this file is no longer needed for the application to run.
If you examine the contents of this file, you'll find JavaScript functions for performing various tasks. These include generating JavaScript alerts in case of errors, and pop-up alerts if the user attempts to navigate away from the web page without saving their changes.
ServiceConfiguration.cscfg
is an Azure configuration file, in XML format. This file is used for storing settings when applications are deployed to Windows Azure. If you're familiar with web development but unfamiliar with Azure, ServiceConfiguration.cscfg
is analogous to the web.config
file in an ASP.NET application. This file is important because it enables post deployment modification of settings through the Windows Azure portal. LightSwitch has added these because web.config
cannot be edited in Azure without redeploying the whole application.
Listing 2-1 shows the default contents of the file. You'll find various settings here for configuring the tracing feature that is built into LightSwitch.
<ServiceConfiguration
serviceName="Application1"
xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration">
<Role name="LightSwitchWebRole">
<Instances count="1" />
<ConfigurationSettings>
<!-- A value of true will enable diagnostic logging on the server -->
<Setting name="Microsoft.LightSwitch.Trace.Enabled" value="false" />
<!-- A value of true only lets local access to Trace.axd -->
<Setting name="Microsoft.LightSwitch.Trace.LocalOnly" value="true" />
<!-- The valid values for the trace level are:
None, Error, Warning, Information, Verbose -->
<Setting name="Microsoft.LightSwitch.Trace.Level" value="Information" />
<!-- True indicates that logging sensitive information is OK -->
<Setting name="Microsoft.LightSwitch.Trace.Sensitive" value="false" />
<!-This contains a semi-colon separated list
of categories that will be enabled at the specifed trace level -->
<Setting name="Microsoft.LightSwitch.Trace.Categories"
value="Microsoft.LightSwitch" />
<!-- True indicates http requests should be redirected to https -->
<Setting name="Microsoft.LightSwitch.RequireEncryption" value="true" />
</ConfigurationSettings>
<Certificates>
</Certificates>
</Role>
</ServiceConfiguration>
ServiceDefinition.csdef
is an Azure configuration file. It contains the metadata used by the Windows Azure fabric and includes settings such as roles, service endpoints, and configuration settings.
A notable setting here is the vmsize
attribute. This is used to control the size of the virtual machine when deployed to Azure. The price that you'll pay for hosting is directly related to this setting. By default, this is set to Small
but can be manually changed to ExtraSmall
if you want cheaper hosting. Table 2-1 illustrates the virtual machine options at the time of this writing.
Listing 2-2 shows the default contents of the ServiceDefinition.csdef
file. You'll see the elements that relate to configuration settings, bindings, endpoints, and certificates.
<ServiceDefinition
name="Application1"
xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="LightSwitchWebRole"
vmsize="Small"
enableNativeCodeExecution="true">
<ConfigurationSettings>
<Setting name="Microsoft.LightSwitch.Trace.Enabled" />
<Setting name="Microsoft.LightSwitch.Trace.LocalOnly" />
<Setting name="Microsoft.LightSwitch.Trace.Level" />
<Setting name="Microsoft.LightSwitch.Trace.Sensitive" />
<Setting name="Microsoft.LightSwitch.Trace.Categories" />
<Setting name="Microsoft.LightSwitch.RequireEncryption" />
</ConfigurationSettings>
<Sites>
<Site name="Web">
<Bindings>
<Binding name="HttpIn" endpointName="HttpIn" />
<Binding name="HttpsIn" endpointName="HttpsIn" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="HttpIn" protocol="http" port="80" />
<InputEndpoint name="HttpsIn" protocol="https" port="443"
certificate="SSLCertificate" />
</Endpoints>
<Certificates>
<Certificate name="SSLCertificate" storeLocation="LocalMachine"
storeName="My" />
</Certificates>
</WebRole>
</ServiceDefinition>
In several of the LightSwitch projects, you'll find folders called GeneratedArtifacts
. These folders contain code that is autogenerated by LightSwitch.
The ApplicationDefinition.lsml
(LightSwitch Markup Language) file (mentioned in Chapter 1) is the most important file in LightSwitch. The definition and details of screens and queries are defined in this file. You'll find this file in the Data
folder.
All other projects in the solution reference this file. Figure 2-3 shows the ApplicationDefinition.lsml
file in the Data
folder, and a reference to it in the Server
project.
Because the ApplicationDefinition.lsml
file contains so much content, it often causes contention when multiple developers are working together on a project through source control.
Although the official recommendation is not to manually edit this file, there are some features and fixes that can be performed only through a manual edit. Cloning a LightSwitch screen is one example requiring you to manually edit the LSML. We strongly recommend that you close out of LightSwitch and back up the LSML file before editing.
To illustrate the LSML, we'll create an application that contains a Customers
table and three screens based on the search, create, and detail templates. Listing 2-3 shows an outline of the LSML file that is generated.
<?xml version="1.0" encoding="utf-8" ?>
<ModelFragment xmlns="http://schemas.microsoft.com/LightSwitch/2010/xaml/model"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application Name="LightSwitchApplication"
Version="1.0.0.0"
DefaultNavigationItem="!module/NavigationItems[Tasks]"
Shell=":Standard"
Theme=":Blue">
</Application>
<EntityContainerGroup Name="DataWorkspace">
</EntityContainerGroup>
<EntityContainer Name="ApplicationData" IsIntrinsic="True">
<SubmitOperation Name="SaveChanges" />
<EntitySet CanDelete="True"
CanInsert="True"
CanUpdate="True"
EntityType="Customer"
Name=" Customers" />
<QueryOperation Name=" Customers_Single"
ReturnType=" Customer">
</QueryOperation>
<QueryOperation Name=" Customers_SingleOrDefault"
ReturnType="Customer">
</QueryOperation>
<QueryOperation Name="Customers_All"
ReturnType="Customer*">
</QueryOperation>
</EntityContainer>
<DataService DataProvider="EntityFrameworkDataProvider"
EntityContainer="ApplicationData"
Name="ApplicationDataMapping" />
<EntityType Name="Customer">
….
</EntityType>
<Screen Name="CustomerDetail">
….
</Screen>
<Screen LaunchMode="Multiple" Name="CreateNewCustomer">
….
</Screen>
<Screen Name="SearchCustomers">
….
</Screen>
</ModelFragment
In Chapter 1, you learned about the model-based architecture behind LightSwitch. You may recognize that the XML elements in this file correspond to the LightSwitch building blocks that were described in that chapter.
The Application
element contains the details that relate to the client application such as shell, theme, and menu navigation contents.
You'll find an EntityContainer
element for each of the data sources in your application. The IsIntrinsic
attribute indicates to LightSwitch that the specified database is the intrinsic database. This is the database that is defined by, and deployed with, your LightSwitch application.
Within this element, you'll find EntitySet
elements for each table. QueryOperation
elements define the operations for retrieving records from a given entity set.
An EntityType
element exists for each table, and child elements define the columns and data types within the table.
Finally, the contents of screens are saved in Screen
elements. If you've ever closed out of the screen designer without saving changes, you would have been prompted to save your changes to the ApplicationDefinition.lsml
file. The reason you receive this dialog box is that the screen details are contained in the screen
elements of the LSML.
Here's an example of where you might want to manually modify the LSML file. Out of the box, LightSwitch doesn't support the notion of nested navigation groups. Navigation groups are used by LightSwitch shells to present the UI for launching screens. To overcome this limitation, you can manually modify the LSML to create a nested navigation menu.
The navigation hierarchy is defined in the Application
section of the LSML. Listing 2-4 shows an outline of this section.
<Application Name="LightSwitchApplication"
Version="1.0.0.0"
DefaultNavigationItem="!module/NavigationItems[Tasks]"
Shell=":Standard"
Theme=":Blue">
<Application.Methods>
<ApplicationMethod Name="ShowCustomerDetail">
<ApplicationMethod.Attributes>
<ShowScreenMethod TargetScreen="CustomerDetail" />
</ApplicationMethod.Attributes>
<ApplicationMethodParameter Name="CustomerId"
ParameterType=":Int32" />
</ApplicationMethod>
<!--Comment - Additional <Application.Methods> elements
appear here for each screen-->
<Application.NavigationItems>
<!--Comment - Navigation items appear here - further details in Listing 2-5-->
</Application.NavigationItems>
<!--Comment - ApplicationCommand elelments are the 'links' for opening new screens
<ApplicationCommand Name="ScreenCommandShowCreateNewCustomer"
Target="!module/Methods[ShowCreateNewCustomer]" />
<ApplicationCommand Name="ScreenCommandShowSearchCustomer"
Target="!module/Methods[ShowSearchCustomer]" />
</Application>
You'll find multiple <Application.Method>
elements for each screen in your application. Toward the end of the <Application>
element, the ApplicationCommand
elements point to the methods that are defined earlier.
The important part that defines the navigation hierarchy belongs inside the <Application.NavigationItems>
element. Listing 2-5 shows the snippet LSML that you would use to create a nested hierarchy. In this example, Group1
and Group3
are top-level groups. Group2
is a child of Group1
.
<Application.NavigationItems>
<ApplicationNavigationGroup Name="Group1">
<ApplicationNavigationGroup.Attributes>
<DisplayName Value="Main Group 1" />
</ApplicationNavigationGroup.Attributes>
<ApplicationNavigationGroup Name="Group2">
<ApplicationNavigationGroup.Attributes>
<DisplayName Value=" Group 1 SubMenu" />
</ApplicationNavigationGroup.Attributes>
<ApplicationNavigationLink
Command="!module/Commands[ScreenCommandShowCreateNewCustomer]"
Name="link2" />
</ApplicationNavigationGroup>
</ApplicationNavigationGroup>
<ApplicationNavigationGroup Name="Group3">
<ApplicationNavigationGroup.Attributes>
<DisplayName Value="Main Group 2" />
</ApplicationNavigationGroup.Attributes>
<ApplicationNavigationLink
Command="!module/Commands[ScreenCommandShowSearchCustomer]"
Name="link3" />
</ApplicationNavigationGroup>
</Application.NavigationItems>
The <ApplicationNavigationGroup>
element defines a navigation group. Tasks and Administration are groups that appear by default in a LightSwitch application. These <ApplicationNavigationGroup>
elements can be nested inside each other to create a nested hierarchy. Figure 2-4 shows a more realistic example of what a nested navigation group would look like.
In this illustration, Products and Customers are children of the Tasks group. The Products group contains the child groups Food Items and Non Food Items. If you collapse a parent group, all child groups are collapsed at the same time. For example, collapsing Products hides both the Food Items and Non Food Items groups.
Although this technique works against the standard LightSwitch shell, it isn't guaranteed to work against other third-party shells.
The important point about this demonstration is that it introduces you to the contents of the LSML file and provides an example of why you might want to manually edit it.
The Server
project is a full .NET 4.0 class library and contains the logic that is executed on the server. Any code that you've written to handle data source events and validation logic is added to this project.
As soon as you write some code that handles a data source event against a table in your intrinsic database, a UserCode
folder is created. Your code is then placed inside a file called ApplicationDataService.vb
or ApplicationDataService.cs,
depending on your chosen language.
If you were to attach to an external database called Northwind and write some code to handle a data source event for a table in the Northwind database, this code would be created in a file called NorthwindDataService.vb
or NorthwindDataService.cs
. As you saw in Chapter 1, a data service is created for each data source in your application. This explains why the term DataService
in used in the file names. The event-handling code that you write for any entity in a data source is saved in a single data service file.
Examples of data source events are the events that make up the save pipeline. These are shown in the following list.
Deleted
Deleting
Inserted
Inserting
Updated
Updating
Validating
Server access control events such as CanDelete
, CanInsert
, and CanRead
are also saved in the DataService
file. The query method code that you write to handle events in the query pipeline such as PreprocessQuery
will also find itself in the file.
You can also use the ServerGenerated
project to store various application settings. In Chapter 14, you'll learn how to send emails from the server. Rather than hard-coding the SMTP server address into your code, the address can be stored in a settings file, which makes it possible to change this setting after deployment.
The ServerGenerated
project is an ASP.NET 4.0 that's executed on the server. You'll find a web.config
file in this project that contains the connection string to your intrinsic database.
The files that support the Entity Framework model are also autogenerated into this folder. These include the files ApplicationData.ssdl
, ApplicationData.csdl
, and ApplicationData.msl
. You'll also find .MSL, .CSDL, and .SSDL files for each additional data source that is defined in your application.
SSDL stands for Store Schema Definition Language and defines the schema of the tables at a SQL Server level. CSDL stands for Conceptual Schema Definition Language, and this defines the entities and relationships that are visible to LightSwitch.
In LightSwitch, there is always a one-to-one relationship between entities and tables. However, the Entity Framework allows for more-complex mappings, and a mapping layer defines the relationship between the conceptual and logical store layers. These mappings are stored in an MSL file, which stands for Mapping Schema Language. Figure 2-5 illustrates the relationships between CSDL, MSL, and SSDL files.
The client project is a Silverlight 4.0 class library project. It contains the client-side business logic that's executed on the client. For example, if you write some code to handle a button click, the code ends up in this project. Because this is a Silverlight project, only references to Silverlight DLLs can be added to this project.
As soon as you write any screen-related code, a UserCode
folder is created and the code's file is placed inside this folder. If you create a Customer Detail screen, for example, any code that you write is added into a file called CustomerDetail.vb
(or CustomerDetail.cs
). Separate screen code files are generated for each screen, with file names that match the name of the screen. If a screen is renamed, LightSwitch automatically renames the underlying screen code file. The screen code file contains the user code that you write to handle the following screen events:
Activated
Closing
Created
InitializeDataWorkspace
Run
SaveError
Saved
Saving
The Client
project also contains a file called Application.vb
(or Application.cs
). This Application
file contains the user code that you would write to control security. For example, if a CustomerDetail_CanRun
method is created to control who can access the screen, this method is saved into the Application
code file.
The ClientGenerated
project is a Silverlight 4.0 application project. The main purpose of this project is to create a Silverlight XAP file.
An XAP file is a Silverlight Application Package and contains a compiled Silverlight application. Just like the Microsoft Office DOCX and XLSX files, XAP files are zip files that contain the files that are needed for the LightSwitch application to run. Renaming a XAP file to ZIP and opening it reveals the content.
After building a LightSwitch application, you can find the XAP file in the inReleaseWeb
or inDebugWeb
directory, depending on the build type. Assuming that you've called your LightSwitch application OfficeCentral
, the file will be named OfficeCentral.Client.Xap
. The XAP file contains the DLLs that are built from the Client
and ClientGenerated
projects, dependent DLLs, the LSML file, and an XAML file containing the shell definition.
Another important file that you'll find inside the XAP file is the AppManifest.xaml
file. This file defines the DLLs that are included in the XAP. Listing 2-6 illustrates an example AppManifest
file. The EntryPointAssembly
attribute indicates that Microsoft.LightSwitch.Client.Internal.dll
is the main assembly for the application. An instance of the Microsoft.LightSwitch.Runtime.Shell.Implementation.App
class is instantiated when your LightSwitch application starts. The RuntimeVersion
attribute defines the Silverlight version the application is built for, and the remainder of the file defines associated DLL files.
<Deployment
xmlns="http://schemas.microsoft.com/client/2007/deployment"
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
EntryPointAssembly="Microsoft.LightSwitch.Client.Internal"
EntryPointType="Microsoft.LightSwitch.Runtime.Shell.Implementation.App"
RuntimeVersion="4.0.50826.0">
<Deployment.Parts>
<AssemblyPart x:Name=" OfficeCentral.ClientGenerated"
Source=" OfficeCentral.ClientGenerated.dll" />
<AssemblyPart x:Name="Application.Common" Source="Application.Common.dll" />
<AssemblyPart x:Name=" OfficeCentral.Client" Source=" OfficeCentral.Client.dll" />
<AssemblyPart x:Name="Microsoft.LightSwitch.Base.Client"
Source="Microsoft.LightSwitch.Base.Client.dll" />
<AssemblyPart x:Name="Microsoft.LightSwitch.Client"
Source="Microsoft.LightSwitch.Client.dll" />
.........
</Deployment.Parts>
</Deployment>
The ClientGenerated
project can be used to make resources available to the client. In Chapter 11, you'll learn how to create reports by using Microsoft Word automation. A DOT Word template file provides the template on which the report is based. The ClientGenerated
project is the mechanism that enables the DOT file to be distributed to the client.
The Common
project contains code that's executed on both the client and server. This project is a plain Silverlight 4.0 class library project. However, the initial assembly references are set to those belonging in the portable class library subset.
Portable class libraries were introduced in .NET 4.0. These types of libraries can run on multiple .NET Framework platforms. In LightSwitch, the assembly built from the Common
project is called from both the Silverlight client and ASP.NET server applications.
You'll find a UserCode
folder in the Common
project. This folder contains the user code that you write for each entity. For example, the Created
, Changed
, and Compute
methods are saved here. The GeneratedArtifacts
folder contains a series of autogenerated code for each entity.
SQL Server plays a major role in LightSwitch. This section shows you where your data is saved and why SQL Server Express is required, examines some of the inner workings of user instances, and describes how you can diagnose issues by using SQL Profiler.
When you create a new LightSwitch project, an intrinsic database called ApplicationData
is created in the project folder. This data source is the default place where user tables are created. The LightSwitch security tables containing users and roles are also created here. You'll find the database file at bindataApplicationData.mdf
.
If you're not too familiar with SQL Server, the MDF file is the primary file that is used for storing the data and database objects. Tables, views, indexes, constraints, and stored procedures are examples of the types of objects that are stored in the MDF file. When debugging applications, an ApplicationData.ldf
file is created in the same directory as the MDF file. The LDF file contains the contents of the SQL Server transaction log.
Caution This intrinsic database is designed to store temporary data for use during debugging time. This data is not deployed with the application, and there may be times when the LightSwitch IDE has to delete the data in order to achieve a schema change.
Some users may prefer to host the intrinsic database by using a non-Express version of SQL Server, particularly if a full version of SQL Server is available on the local development machine. This scenario is not supported, and errors will occur if you modify the database connection string in the web.config file to point to a non–SQL Express instance. SQL Express is required so that LightSwitch projects can be shared between users. By using the Auto Attach feature of SQL Express, both the database and LightSwitch project files are self-contained in a single folder. This allows you to easily back up and share your LightSwitch project.
Note that the SQL Server Express requirement does not apply to deployed applications. During deployment, you can choose to host the intrinsic database in a full version of SQL Server, SQL Express, or even SQL Server Azure if you wish.
Unfortunately, many LightSwitch developers first encounter the term SQL user instance following a failure to connect to the intrinsic database. In order to explain what this is, we'll describe the problems that user instances were designed to solve.
In simple terms, an instance is a copy of SQL Server that runs on a machine. Each instance has its own settings and logins, and listens on a distinct port number.
The usual way of accessing the contents of a SQL Server database file is to first attach it in SQL Server. If you're using an edition of SQL Server other than SQL Server Express, this step must be carried out. After you do this, a security login must be created, and that login added to the user list for the database. For developers, this is a cumbersome process. To make life easier, SQL Server Express includes an Auto Attach feature. This allows you to use a SQL Express database, just by specifying a database file name in the connection string. There's no need for you to do anything else in SQL Server Management Studio, or to carry out any additional setup tasks. This feature makes it really easy for you to use databases and share them with others.
The traditional way of attaching a database can present a second challenge. This is because you must have SQL Server administrative privileges to attach a database. The exact problem is that you might not be an administrator, or you might work in a corporate environment where you've been denied the necessary permissions. User instances provide the solution to these problems. They allow you to auto-attach a database without needing any administrative permissions. This feature is found only in the Express version and isn't available in any other edition of SQL Server.
A user instance is like a normal instance, but is created on demand when a connection to the database is first made. The user instance runs under the security context of the user who initiates the connection. This therefore gives the user full administrative control over the instance, even if the user doesn't have administrative privileges on the machine.
User instances are hosted by a parent SQL Server Express instance. If you want to use a user instance, you'd create a connection to the parent SQL Server Express instance and specify the user instance flag in the connection string.
Tip Chapter 17 contains various tips to help you diagnose and solve SQL Server problems.
In this section, we'll show you how to use Server Explorer to connect to your intrinsic database. By connecting to the database in this way, you can work with data inside of Visual Studio without having to run your application.
You can also create database diagrams that enable you to view multiple tables and relationships in your database. This allows you to see the bigger picture, because the LightSwitch designer lets you view only one table at a time.
In order to view the intrinsic database in Server Explorer, open Server Explorer by clicking View Server Explorer, or click Ctrl+Alt+S. After Server Explorer appears, right-click the Data Connections icon and select the Add Connection option, as shown in Figure 2-6. The Add Connection dialog box appears (see Figure 2-7).
In the Add Connection dialog box, enter the SQL Server Express instance name into the Server Name text box. Select the option to Attach a Database File and provide the path to your ApplicationDatabase.mdf
file. Now click the Advanced button, and in the Advanced Properties dialog box, set the User Instance option to True, as shown in Figure 2-8.
Complete the steps in the Add Connection dialog box. When you are finished, the connection to your intrinsic database will be shown in Server Explorer, as you can see in Figure 2-9.
Notice how all of the database objects are visible beneath the Tables
node. You'll also see a set of aspnet
_* tables. These tables are used by LightSwitch to manage security, users, and roles.
By using the options that appear in the Database Diagrams
node, you can create and manage your own database diagrams.
It's important to bear in mind that additional tables or columns added through Server Manager will not be reflected in your LightSwitch model. Therefore, you should continue to design your tables by using the LightSwitch table designer.
Note When the time comes to deploy your application, you might want to include the data that you've entered at debugging time. For example, you might want to script out the data that you've entered so that you can add it to your deployment package. Attaching the database allows you to get to your data and to carry out this task..
SQL Server Profiler is a very useful debugging tool. It allows you to see the exact SQL that LightSwitch generates and submits to SQL Server. You'll find it included in some of the paid-for versions of SQL Server. If you don't have access to SQL Server Profiler, a free alternative is AnjLab SQLExpressProfiler. This product is open source, and you can download it from http://sites.google.com/site/sqlprofiler/
.
SQL Server Profiler can help you uncover some of the inner workings of LightSwitch. We'll show you how to use Profiler now because we'll refer to the traces that it creates later in the book.
During debugging time, LightSwitch hosts the intrinsic database by using a user instance of SQL Server Express. If you want to start a trace in Profiler, you can't connect to a SQL Server user instance by using TCP/IP and a server name. Instead, you have to use named pipes. To find out the address to use, connect to SQL Server Express by using Management Studio, or by using Server Explorer as described earlier.
If you're using Server Explorer, create a new connection to the master database of your SQLEXPRESS instance. Now start your LightSwitch application. Next, create a new query by choosing Data New Query. Execute the SQL command shown in Listing 2-7 to return the pipe name, as shown in Figure 2-10.
SELECT owning_principal_name,instance_pipe_name FROM sys.dm_os_child_instances
Now that you know the pipe name, you can use SQL Server Profiler to trace your intrinsic database. Connect to the server by using the pipe name (shown in Figure 2-11) and begin a trace. Perform some actions in your LightSwitch application, and the results will be shown in the trace (see Figure 2-12).
Even the best programmers will make mistakes when writing applications. Fortunately, the Visual Studio IDE contains some powerful tools that will help you detect and correct problems.
You may have some familiarity using the debugger. If not, this section will help you understand some of the basics before moving on further into this book.
Breakpoints are a key part of debugging. You can insert these into your code by clicking on the left margin of the code window. When the code execution reaches the breakpoint, the program stops executing temporarily. You can then step through the remaining code one line at a time by pressing F10, or by clicking the Step Over button. If you want to dive into functions or subprocedures that are being called in the current line, pressing F11 allows you to Step Into the child procedures.
If you want to skip over several lines of code without having to step over each line individually, you can place the cursor on a line beneath and select the Run to Cursor option, as shown in Figure 2-13.
If during a session you want to run your application for a while without stopping at breakpoints, you can select the Disable All Breakpoints option under the Debug menu. When you're ready to break into breakpoints again, you can select the Enable All Breakpoints option to continue.
The Locals window, shown in Figure 2-14, allows you to keep track of local variables. These variables appear beneath the Name column, and additional attributes can be shown by expanding the tree nodes.
The Autos window is one of the main windows used during debugging. This window displays the values of variables and properties as they are evaluated by the compiler. These values disappear when the objects fall out of scope.
Unlike the Autos window, the Watch window allows you to view values throughout the execution of a program. Figure 2-15 illustrates how a watch can be added through the Autos window by selecting the Add Watch option.
The Immediate window, shown in Figure 2-16, is a very versatile tool. It allows you to easily interrogate variable values by using the ?
operator. The Immediate window provides IntelliSense assistance to help you construct the correct syntax. Unlike the other debugging windows, the Immediate window allows you to change the values of properties and variables while debugging.
The Command window, shown in Figure 2-17, allows you to run Visual Studio commands such as File.SaveAll
. You don't need to be in debug mode to run commands in the Command window. As in the Immediate window, the commands in the Command window also support IntelliSense.
While in the Command window, you can switch to the Immediate window by typing immed
. Conversely, you can switch to the Command window from the Immediate window by typing cmd
.
The Debug Attach to Process menu option allows you to attach processes to the debugger. For example, if you want to debug using the Firefox browser instead of Internet Explorer, you can attach the Firefox Silverlight client to the debugger by attaching to the plugin-container.exe (type Silverlight)
process. This is shown in Figure 2-18.
Experienced developers will often extend queries by using the _PreProcessQuery
or _Executed
methods. When LINQ or other coding errors are encountered, these exceptions will be swallowed by LightSwitch. A red cross appears against any grids that are bound to the query, and no indication is given as to what the exact cause of the error might be.
To help diagnose such errors, failed queries raise the _ExecuteFailed
event, giving access to the underlying exception. Handling this event and placing a breakpoint on the method (Figure 2-19) allows you to interrogate the exception by using tools such as the Immediate or Autos windows.
Let's imagine that you've written a complex piece of screen code. This code performs an operation that takes a long time to complete. When your code runs, your application still remains responsive. In other words, it can still respond to mouse clicks and keystrokes, and provides a positive experience for the user. Your application can do this because LightSwitch uses two threads.
In LightSwitch, all UI tasks and user interaction is carried out by a UI thread (also known as the main dispatcher). Each screen gets its own thread for carrying out tasks that are not UI related. This thread is called the screen thread, or logic thread. Whenever you write any user code on a screen, the operation is executed on the screen thread by default.
Let's say that you want to perform a task that requires some user intervention. For example, imagine that you want to show a File Open dialog box. You must write code to specifically carry out this task on the UI thread. If you fail to do this, LightSwitch throws an exception.
If you're debugging a piece of code, it's really useful to be able to identify what thread you're running on. To find this out, place a breakpoint in your code. You can then use the Immediate window and call the CheckAccess
method, as shown in Listing 2-8. If the result is true
, your code is running on the UI thread. If false
, it's running on the logic thread.
Microsoft.LightSwitch.Threading.Dispatchers.Main.CheckAccess()
There are three dispatchers that you can use in LightSwitch. These allow you to execute code on a different thread. The following list summarizes the LightSwitch object that you can use to reference the dispatcher.
Dispatchers.Main
Screen.Details.Dispatcher
Application.Details.Dispatcher
In addition to the UI and logic dispatchers, the application dispatcher is responsible for running global application code that isn't associated with any specific screen.
Note If you need to diagnose problems after deployment, the tracing feature in LightSwitch can help you to do that. You can find out more about this in Chapter 17.
You may have discovered that LightSwitch projects take up a lot of space on the file system. The size taken up by an empty project is around 89MB. After building the project for the first time, the size increases to around 132MB, even though there are still no tables or screens in the project.
The size of LightSwitch projects can present a problem when trying to back up or share your work with others. Because the bin
and obj
folders are regenerated following each build, these folders can be deleted prior to backing up. If you choose to do this, however, make sure not to delete the file bindataApplicationData.mdf
, because this contains your design-time intrinsic database.
You can simplify this task by creating a batch file to automate the process. The content of such a script is shown in Listing 2-9.
rd /q /s BinDebug
rd /q /s BinRelease
rd /q /s ClientBinDebug
rd /q /s ClientBinRelease
rd /q /s ClientobjDebug
rd /q /s ClientobjRelease
rd /q /s ClientGeneratedBinDebug
rd /q /s ClientGeneratedBinRelease
rd /q /s ClientGeneratedobjDebug
rd /q /s ClientGeneratedobjRelease
rd /q /s CommonBinDebug
rd /q /s CommonBinRelease
rd /q /s CommonobjDebug
rd /q /s CommonobjRelease
rd /q /s ServerBinDebug
rd /q /s ServerBinRelease
rd /q /s ServerobjDebug
rd /q /s ServerobjRelease
rd /q /s ServerGeneratedinDebug
rd /q /s ServerGeneratedinRelease
rd /q /s ServerGeneratedin
rd /q /s ServerGeneratedobjDebug
rd /q /s ServerGeneratedobjRelease
Create this file in the root folder of your project and execute it in order to delete all extraneous files. The remaining files and folders can be zipped into a compressed file to further reduce file size.
This chapter has covered the following topics:
You can switch your LightSwitch project into File view by clicking a button in Solution Explorer. This reveals the projects that make up a LightSwitch solution. The projects that you'll find are as follows:
Client
contains the client-side business logic.ClientGenerated
builds the Silverlight XAP file.Server
contains server-side business logic.ServerGenerated
contains the ASP.NET server project.Common
contains the common business logic used on the client and server.ApplicationDefinition.lsml
is a very important file and contains the definitions of all screens and entities in your application. In some advanced scenarios, you'll need to manually modify this file by using a text editor. The example that we've given in this chapter shows you how to create nested navigation groups. Whenever you modify this file outside of LightSwitch, we strongly recommend that you back up the file.
The intrinsic database stores the tables that you create in LightSwitch. During design time, a temporary database is created in the location bindataApplicationData.mdf
. This temporary database is used to store your data between debugging sessions. The data that you enter at design time won't be deployed with your final application. If you need to get to this data, you can connect to the ApplicationData.mdf
file by using Server Explorer or SQL Server Management Studio.
The intrinsic database must be hosted by SQL Server Express at development time (although there isn't any limitation for deployed applications). The SQL Server Express requirement makes it easy for you to share LightSwitch projects. If someone else opens a project that you've created, there isn't any need for them to create or attach a corresponding database. The auto-attach, and user instance features of SQL Server Express make this possible.
Finally, you've seen how to debug LightSwitch applications by using the debugger. When you're debugging problems with queries, it's a good idea to place a breakpoint in the ExecuteFailed
method. This allows you to get to the actual exception. When debugging threading issues, you can call the CheckAccess
method on the main dispatcher to work out what thread you're running on.