• Shortcuts : 'n' next unread feed - 'p' previous unread feed • Styles : 1 2

» Publishers, Monetize your RSS feeds with FeedShow:  More infos  (Show/Hide Ads)


Date: Friday, 16 Aug 2013 14:21

A lot of times LightSwitch customers will run into an error in the product and post a question on the forums but the LightSwitch development team needs more information about the error.  This blog post describes how you can help the LightSwitch development team determine the source of those kinds of errors you may encounter.  Unexpected errors (or exceptions as we call them) within the product can manifest themselves either by an error message, a crash, lack of response (hang), or when an expected behavior doesn’t occur.  By providing an exception stack trace in your forum posts, it provides valuable information to the development team and helps us help you.

Exception Lead-In

Before beginning the process of debugging, you’ll want to follow the necessary steps in Visual Studio or your LightSwitch app that reproduce the exception but stopping just prior to the last step that actually causes the exception.  If you attach and debug prior to all these steps you may encounter a bunch of exceptions that are unrelated to the issue or performance of the process may be degraded enough that will make you annoyed.  So just get to the point right before the exception occurs and then follow the instructions below.

Attaching to the Process

The next step is to identify which process to debug.  This handy flowchart can help you determine which process you should be attached to in order to retrieve the exception stack trace:

image

Note that if the issue you’re investigating occurs within your running application while you are running it from within Visual Studio via F5, Visual Studio will automatically be attached to both the client and server processes.  In all other cases, you’ll need to manually attach to the process.  Of course, if the issue occurs within Visual Studio itself, you’ll need to launch another instance of Visual Studio to attach to the original instance since a given VS process cannot attach to itself.

To manually attach to the process, go to “Tools –> Attach to Process…” in Visual Studio.

image

In the dialog that opens, select the name of the process as indicated by the flowchart above.  This will only allow you to attach to the process if it is running on the local machine.  If you want to attach to a remote process (for example, attach to the IIS process on a remote machine), you’ll need to follow the instructions in this MSDN article: Setup Remote Debugging.  If the process is hosted on a machine you don’t have access to, like Azure, you won’t be able to follow the debugging instructions described in this post.  Instead, you’ll need to use diagnostic tracing as described in this post: Diagnosing Problems in a Deployed 3-Tier LightSwitch Application.

Configure for Debugging

Now that Visual Studio is attached to the process, it needs to be properly configured to break on exceptions in order to see the stack trace of the exceptions.

The first thing to do is to ensure that VS is configured to debug code that you don’t own.  Visual Studio has a feature called “Enable Just My Code” that is enabled by default which prevents you from debugging code that isn’t yours.  To turn it off, follow these steps:

  1. Go to Tools –> Options.
  2. If necessary, click the “Show all settings” check box at the bottom of the dialog if the “Debugging” node doesn’t show up in the tree.
  3. In the Options dialog, navigate to Debugging –> General in the tree.
  4. Ensure that the “Enable Just My Code” check box is not checked.

image

 

The next thing is to configure VS so that it will break when an exception is thrown.  To do this, open the Exceptions dialog: Debug –> Exceptions.  In the Exceptions dialog, find the category of exceptions you want to break on and check its check box in the “Thrown” column.  For server and Silverlight client debugging, you’ll want to use the Common Language Runtime Exceptions; for HTML clients, you’ll want to use the JavaScript Runtime Exceptions.

image

This will break on all exceptions of that category.  A lot of times there will be exceptions thrown that are irrelevant to the actual issue.  These are normal and are handled by the LightSwitch code.  If you know the specific exception type that you want to break on, you can configure this dialog to break only on that exception type by drilling into the Common Language Runtime Exceptions node and finding the exception or by clicking the Find button and searching for it that way.

Reproduce the Exception

You’re now ready to do the final step in Visual Studio or your LightSwitch app that actually causes the exception to occur.  Once you do that, you’ll see an exception message appear in Visual Studio that looks like this:

image

Or like this if you’re debugging an HTML client:

image

 

As mentioned earlier, there can be exceptions that are thrown that are properly handled by LightSwitch and irrelevant to your actual issue.  You’ll want to work with someone on the LightSwitch development team via the forums or e-mail to determine which exception is the one that is relevant.  If you know the exception is not relevant, you can continue execution by clicking the “Continue” button.

Collect Exception Information

Once you’ve found the exception, click the “Copy exception detail to the clipboard” in the exception window if it’s a .NET exception and paste the result into your favorite text editor.  If it’s a JavaScript exception, there won’t be a link to do this so just skip that step.  Now, you’ll still need to collect a little more information since that exception detail won’t include a detailed stack trace.  Click the “OK” or “Break” button in the exception window to dismiss the window.  Open the Call Stack window in Visual Studio: Debug –> Windows –> Call Stack.  Select all of the lines in it (Ctrl+A) and copy it to the clipboard (Ctrl+C).

image

Paste that text along with the other exception detail you collected into the text editor.  You’ve now collected enough information to pass along to the LightSwitch development team.  Of course, along with the exception information, you should still describe the set of steps that reproduce the issue.

HTML Clients

If you’re debugging a JavaScript exception, the stack trace will probably have a lot of single letters for function names.  This happens because you’re app is configured to use the minified versions of the runtime JavaScript files.  To provide a more informative stack trace, change your default.htm file of your HTML client and remove “.min” from all of the filenames of the referenced scripts.

image

Then follow the steps to reproduce the issue again.  This time it will provide the friendly function names in the stack trace which is much more useful.  Be sure to revert your changes to the default.htm file when you’re done debugging.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch, Debugging"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 25 Jun 2013 18:57

When you enable Windows or Forms authentication in a LightSwitch app, a set of SQL tables are used to store the user and role data.  But did you know that you can customize how and where LightSwitch gets the user and role data?  You don’t have to use the default set of SQL tables that LightSwitch generates in its intrinsic database.  This post describes in detail how you can go about customizing the management of users and roles in your LightSwitch app.

Extensible Design

LightSwitch makes use of many APIs within ASP.NET.  Among those are the provider classes for user and role management.  You can learn more about these providers and their associated APIs on MSDN:

The great thing about this provider model is that it is configurable outside of source code.  You can configure your app, defining which providers to use and their settings, by editing your web.config file.  And since all providers have a common set of base classes, LightSwitch doesn’t need to know which provider type it’s using; the web.config file and ASP.NET dictate which providers LightSwitch uses.

There are a set of base provider classes that we’re interested in here:

  • System.Web.Security.MembershipProvider: This class defines the interface used to access user information such as the login name and password of a user.
  • System.Web.Security.RoleProvider: This class defines the interface used to access role information (e.g. SalesPerson or Manager).
  • System.Web.Profile.ProfileProvider: This class defines the interface used to access custom user-specific data.  This is data that the application itself wants to track along with the user.  ASP.NET doesn’t track any data of its own here; this is all application-specific.

LightSwitch makes use of each of these provider types and each of them can have a custom implementation that LightSwitch will invoke.

How LightSwitch Works

Before I get into how you can customize the user and role management, I wanted to describe how LightSwitch configures things.  Understanding this will allow you to be better informed when time comes to do the customizing.

LightSwitch makes use of the following implementations of the previously mentioned base provider classes:

Each of these classes are implementations of the base provider interface such that they make use of a set of SQL tables to store and retrieve their respective data.  For example, the SqlMembershipProvider implementation makes use of a combination of the aspnet_Membership and aspnet_Users tables contained in the LightSwitch intrinsic database.

If you enable authentication in your LightSwitch app, save, and open your web.config file, you’ll see how LightSwitch configures the use of these providers.  For more information on configuring authentication in your LightSwitch app, see LightSwitch Authentication and Authorization.

Membership Provider

LightSwitch uses the membership provider to store the users that have access to the application.  When you log into a LightSwitch app with your username and password, for example, LightSwitch makes use of the membership provider to ensure 1) you exist as an application user and 2) your password matches.

1: <membership defaultProvider="AspNetMembershipProvider"> 2: <providers> 3: <clear /> 4: <add 5: name="AspNetMembershipProvider" 6: type="System.Web.Security.SqlMembershipProvider" 7: connectionStringName="_IntrinsicData" 8: applicationName="Application10" 9: requiresUniqueEmail="false" 10: requiresQuestionAndAnswer="false" /> 11: </providers> 12: </membership>
The snippet above shows how LightSwitch configures the membership provider when Forms authentication is being used.  I’ll explain each of the lines in that snippet so it all makes sense:

Line #1: The membership element configures the ASP.NET membership management.  It contains a defaultProvider attribute which references the name of membership provider defined below that should be used by default.

Line #2: The providers element defines the collection of membership providers and their configurations.  Obviously, this implies you can define multiple membership providers in this section which ASP.NET supports.  LightSwitch does not support multiple providers.  Only the membership provider marked as the default (via the defaultProvider attribute on the membership element) will be used.

Line #3: The clear element simply ensures that the providers element collection is cleared prior to adding the membership provider.  This isn’t strictly necessary but it ensures that there are no extraneous providers included in the collection that may have been added by fancy things like web.config inheritance.

Line #4: The add element defines which membership provider should be added to the collection and how it should be configured.  It has several attributes that are configured by LightSwitch by default.

Line #5: The name attribute is an identifier for the provider within the web.config so that it can be referenced as the default provider.

Line #6: The type attribute is the .NET type name of the membership provider.

Line #7: The connectionStringName attribute is the name of the connection string that this membership provider should used when accessing the database tables.

Line #8: The applicationName attribute is the name of the application with which to associate the membership data.  ASP.NET’s implementation of the SqlMembershipProvider allows you to have multiple applications all share the same database but partition, or share depending on how things are configured, the user information between those applications.  Applications that have membership providers configured with the same application name will share the membership data; if they are different application names, the membership data will be separate between the apps.

Line #9: The requiresUniqueEmail attribute indicates whether a unique e-mail address is required for the user.  By default, SqlMembershipProvider sets this value to true.  LightSwitch doesn’t collect an e-mail address for a user, so this is set to false.

Line #10: The requiresQuestionAndAnswer attribute indicates whether a password question/answer pair is required for the user to allow for password reset and retrieval.  By default, SqlMembershipProvider sets this to true.  Again, since LightSwitch doesn’t use e-mail addresses, this is set to false.

1: <membership defaultProvider="AspNetMembershipProvider"> 2: <providers> 3: <clear /> 4: <add name="AspNetMembershipProvider" type="Microsoft.LightSwitch.Security.ServerGenerated.Implementation.WindowsUserMembershipProvider, Microsoft.LightSwitch.Base.Server, Version=11.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="_IntrinsicData" applicationName="Application10" /> 5: </providers> 6: </membership>

The snippet above shows how LightSwitch configures the membership provider when Windows authentication is being used.  For Windows authentication, LightSwitch continues to use SQL-based storage to track which Windows users have access.  Even in the case where the app has been configured to allow access to any authenticated Windows user, LightSwitch will still make use of this storage to track which app-defined roles are assigned to any of those users.  LightSwitch makes use of a custom implementation membership provider, derived from SqlMembershipProvider that adds some extra logic specific to handling Windows users and also correctly defaults most of the settings which is why you don’t see the requiresUniqueEmail and requiresQuestionAndAnswer settings here.  Note that the type attribute is set using an assembly-qualified type name since this is a custom type that is not defined by ASP.NET.

Role Provider

LightSwitch uses the role provider to store the roles that have been defined within the app and to map those roles to users.

1: <roleManager enabled="True" defaultProvider="AspNetRoleProvider"> 2: <providers> 3: <clear /> 4: <add name="AspNetRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="_IntrinsicData" applicationName="Application10" /> 5: </providers> 6: </roleManager>

The snippet above shows how LightSwitch configures the role provider when any authentication is being used.  It’s pretty much the same structure as the membership snippet.  The only real difference is that the roleManager element has an enabled attribute.  That attribute needs to be set to true in order to enable the use of roles in the ASP.NET API.  Just like with the membership provider, LightSwitch only makes use of the role provider that is defined as the default provider.

Profile Provider

LightSwitch uses the profile provider to store some extra information about the user in the case where Forms authentication is being used.  In general, the profile provider can be used to track other custom data for a user that is not represented in the membership provider/SQL schema.  In the case of LightSwitch, it keeps track of the full name (display name) of a user, so the profile provider is configured to store this data.

1: <profile enabled="True" defaultProvider="AspNetProfileProvider"> 2: <providers> 3: <clear /> 4: <add name="AspNetProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="_IntrinsicData" applicationName="Application10" /> 5: </providers> 6: <properties> 7: <add name="FullName" /> 8: </properties> 9: </profile>

The snippet above shows how LightSwitch configures the profile provider.  It follows the same structure as the other two snippets except for the properties child element.  The profile element contains a properties child element that allows a developer to define the names of properties that should be associated with each user.  In the case of LightSwitch, it defines a FullName property here.  Just as with the other providers, LightSwitch only makes use of the profile provider that is defined as the default provider.

Permission Mapping

ASP.NET has the concepts of users (membership), roles, and profiles of which LightSwitch makes use.  But ASP.NET does not have the concept of permissions, while LightSwitch does.  So LightSwitch defines its own table, named RolePermissions, within the intrinsic database to map roles and permissions as that is how permissions are assigned in LightSwitch apps.  There does not exist an ASP.NET provider that accesses this table; LightSwitch uses technology outside of ASP.NET to access this table.  For this reason, the storage of role-permission mappings is not customizable.  You can customize how and where roles are stored but when LightSwitch needs to map a permission to that role, it always stores that mapping information in the RolePermissions table.

ASP.NET Provider Customization

Now that you understand how LightSwitch configures the ASP.NET providers it uses, let’s get into how you can go about customizing them.  There are a few ways you can go about customizing the providers:

  • Configure provider properties via the web.config
  • Replace with an existing provider class implementation
  • Define a custom provider
Configuring Provider Properties

The easiest but least flexible way to customize an ASP.NET provider is to configure its properties within the web.config file.  For example, if you want to change the maximum number of password attempts allowed for a user from the default of 5 to 10, you would set the maxInvalidPasswordAttempts attribute in the add element of the default membership provider configured by LightSwitch (see line #9):

1: <membership defaultProvider="AspNetMembershipProvider"> 2: <providers> 3: <clear /> 4: <add 5: name="AspNetMembershipProvider" 6: type="System.Web.Security.SqlMembershipProvider" 7: connectionStringName="_IntrinsicData" 8: applicationName="Application10" 9: maxInvalidPasswordAttempts="10" 10: requiresUniqueEmail="false" 11: requiresQuestionAndAnswer="false" /> 12: </providers> 13: </membership>

If you had a separate database location where your ASP.NET users and roles were stored, you could configure your providers to use that database by simply adding a connection string to your web.config file and setting the connectionStringName attributes of your providers to reference that connection string.

Consult the documentation of the provider type in order to determine which properties it defines that are configurable through the web.config file.

Replacing a Provider

If there already exists an implementation of an ASP.NET provider different than the default one used by LightSwitch that you want to use, you can simply configure the web.config file to reference that provider type and LightSwitch will make use of it.  To do this, follow these steps:

  1. Add a reference to the assembly that contains the provider type you want to use from your LightSwitch app’s Server project, being sure to set the “Copy Local” property to true for the assembly reference.  This will ensure that the assembly will be copied to the runtime environment.
  2. Set the add element’s type attribute for that provider to be the assembly-qualified type name of the provider type you want to use.  For example, see line #6:
1: <membership defaultProvider="AspNetMembershipProvider"> 2: <providers> 3: <clear /> 4: <add 5: name="AspNetMembershipProvider" 6: type="SomeLibrary.SomeMembershipProvider,SomeLibrary" 7: connectionStringName="_IntrinsicData" 8: applicationName="Application10" 9: requiresUniqueEmail="false" 10: requiresQuestionAndAnswer="false" /> 11: </providers> 12: </membership>
Defining a Custom Provider

In order to write your own custom provider, you define a class that inherits from the appropriate provider base type (System.Web.Security.MembershipProvider, System.Web.Security.RoleProvider, or System.Web.Profile.ProfileProvider) and update the web.config just as was explained in the previous “Replacing a Provider” section.

MSDN provides good documentation on how to go about implementing a custom provider:

These providers can contain a large number of members that must be implemented in the derived class.  In the case of LightSwitch’s usage of these providers, not all the members need to be fully implemented.  Here’s a list of provider members which LightSwitch uses and, thus, must be implemented (as opposed to just throwing a NotImplementedException):

  • MembershipProvider
    • Properties
      • ApplicationName
      • MaxInvalidPasswordAttempts [Forms authentication only]
      • MinRequiredNonAlphanumericCharacters [Forms authentication only]
      • MinRequiredPasswordLength [Forms authentication only]
      • PasswordFormat
      • PasswordStrengthRegularExpression [Forms authentication only]
    • Methods
      • ChangePassword [Forms authentication only]
      • CreateUser
      • DeleteUser
      • GetAllUsers
      • GetUser(string, bool)
      • ResetPassword [Forms authentication only, “answer” argument will always be null]
      • UnlockUser
      • ValidateUser [Forms authentication only]
  • RoleProvider
    • Properties
      • ApplicationName
    • Methods
      • AddUsersToRoles
      • CreateRole
      • DeleteRole
      • GetAllRoles
      • GetRolesForUser
      • GetUsersInRole
      • RemoveUsersFromRoles
      • RoleExists
  • ProfileProvider [Forms authentication only]
    • Properties
      • ApplicationName
    • Methods
      • DeleteProfiles
      • GetPropertyValues
      • SetPropertyValues

Wrap-up

It was important within the design of LightSwitch that existing technologies were used where appropriate.  In the case of user and role management, ASP.NET already provided a mechanism for this, so we didn’t reinvent the wheel and instead built LightSwitch on top of those APIs.  This allows LightSwitch to be customized in a way that is not unique to LightSwitch but is a familiar experience for ASP.NET developers.

I encourage you to read the MSDN articles that are linked from this blog post.  You can learn a lot of extra information on the APIs and provider customization from those articles.

Please let me know if you have any questions or run into any issues.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch, Security"
Comments Send by mail Print  Save  Delicious 
Date: Thursday, 15 Mar 2012 20:10

In this blog post, I’m going to describe how LightSwitch developers can programmatically access the security data contained in a LightSwitch application.  Having access to this data is useful for any number of reasons.  For example, you can use this API to programmatically add new users to the application.

This data is exposed in code as entities, just like with your own custom data.  So it’s an easy and familiar API to work with.  And it’s available from both client or server code.

First I’d like to describe the security data model.  Here’s a UML diagram describing the service, entities, and supporting classes:

image

SecurityData

This is the data service class that provides access to the security entities as well as a few security-related methods.  It is available from your DataWorkspace object via its SecurityData property.

SecurityData is a LightSwitch data service and behaves in the same way as the data service that gets generated when you add a data source to LightSwitch.  It exposes the same type of query and save methods.  It just operates on the built-in security entities instead of your entities.

Some important notes regarding having access to your application’s security data:
In a running LightSwitch application, users which do not have the SecurityAdministration permission are only allowed to read security data; they cannot insert, update, or delete it.  In addition, those users are only able to read security data that is relevant to themselves.  So if a user named Bob, who does not have the SecurityAdministration permission, queries the UserRegistrations entity set, he will only see a UserRegistration with the name of Bob.  He will not be able to see that there also exists a UserRegistration with the name of Kim since he is not logged in as Kim.  Similarly with roles, if Bob queries the Roles entity set, he can see that a role named SalesPerson exists because he is assigned to that role.  But he cannot see that a role named Manager exists because he is not assigned to that role.

Users which do have the SecurityAdministration permission are not restricted in their access to security data.  They are able to read all stored security data and have the ability to modify it.

In addition to entity sets, SecurityData also exposes a few useful methods:

  • ChangePassword
    This method allows a user to change their own password.  They need to supply their old password in order to do so.  If the oldPassword parameter doesn’t match the current password or the new password doesn’t conform to the password requirements, an exception will be thrown.  This method is only relevant when Forms authentication is being used.  This method can be called by any user; they do not require the SecurityAdministration permission.
  • GetWindowsUserInfo
    This method validates and resolve a Windows account name into a normalized value and retrieve the full name (display name) of that user.  As an example, let’s say that you passed “kim@contoso.com” as the parameter to this operation, it would return back a WindowsUserInfo object with the FullName property set to “Kim Abercrombie” and the NormalizedUserName property set to “contoso\kim”.  If the service is unable to resolve the username parameter to a known account, an exception will be thrown.  This method is only relevant when Windows authentication is being used.  This method can only be called by users that have the SecurityAdministration permission.
  • IsValidPassword
    This method checks whether the supplied password meets the password requirements of the application.  This happens automatically when attempting to add a new user or updating their password but this method allows the caller to preemptively check the password which can be useful for validation UI purposes.  This method is only relevant when Forms authentication is being used.  This method can only be called by users that have the SecurityAdministration permission.

UserRegistration

The UserRegistration entity represents a user that has access to the application.  (In VS 11, it can also represent an Active Directory security group when Windows authentication is being used).  When using Forms authentication, all the UserRegistration properties (UserName, FullName, Password) are required.  When using Windows authentication, only the UserName property is required; FullName is populated dynamically based on the UserName and Password is irrelevant.

Here is some example code using the UserRegistration entity:

C#:

// Create a new UserRegistration (Windows authentication)
UserRegistration user = this.DataWorkspace.SecurityData.UserRegistrations.AddNew();
user.UserName = "contoso\\kim";
this.DataWorkspace.SecurityData.SaveChanges();

// Create a new UserRegistration (Forms authentication)
UserRegistration user = this.DataWorkspace.SecurityData.UserRegistrations.AddNew();
user.UserName = "kim_abercrombie";
user.FullName = "Kim Abercrombie";
user.Password = "mysecretpassword!";
this.DataWorkspace.SecurityData.SaveChanges();

// Iterate through all UserRegistrations
foreach (UserRegistration user in this.DataWorkspace.SecurityData.UserRegistrations)
{
}

// Find a specific UserRegistration (Windows authentication)
UserRegistration user = this.DataWorkspace.SecurityData.UserRegistrations_Single("contoso\\kim");

// Find a specific UserRegistration (Forms authentication)
UserRegistration user = this.DataWorkspace.SecurityData.UserRegistrations_Single("kim_abercrombie");

VB:

' Create a new UserRegistration (Windows authentication)
Dim user As UserRegistration = Me.DataWorkspace.SecurityData.UserRegistrations.AddNew()
user.UserName = "contoso\\kim"
Me.DataWorkspace.SecurityData.SaveChanges()

' Create a new UserRegistration (Forms authentication)
Dim user As UserRegistration = Me.DataWorkspace.SecurityData.UserRegistrations.AddNew()
user.UserName = "kim_abercrombie"
user.FullName = "Kim Abercrombie"
user.Password = "mysecretpassword!"
Me.DataWorkspace.SecurityData.SaveChanges()

' Iterate through all UserRegistrations
For Each user As UserRegistration In Me.DataWorkspace.SecurityData.UserRegistrations
Next

' Find a specific UserRegistration (Windows authentication)
Dim user As UserRegistration = Me.DataWorkspace.SecurityData.UserRegistrations_Single("contoso\\kim")

' Find a specific UserRegistration (Forms authentication)
Dim user As UserRegistration = Me.DataWorkspace.SecurityData.UserRegistrations_Single("kim_abercrombie")

Role

The Role entity represents a grouping of users with common characteristics.  Examples of roles in an application include “Sales Person” and “Manager”.  You can then configure your application security around these roles.

Here is some example code using the Role entity:

C#:

// Create a new role
Role role = this.DataWorkspace.SecurityData.Roles.AddNew();
role.Name = "Manager";
this.DataWorkspace.SecurityData.SaveChanges();

// Iterate through all Roles
foreach (Role role in this.DataWorkspace.SecurityData.Roles)
{
}

// Find a specific role
Role role = this.DataWorkspace.SecurityData.Roles_Single("Manager");

VB:

' Create a new role
Dim role As Role = Me.DataWorkspace.SecurityData.Roles.AddNew()
role.Name = "Manager"
Me.DataWorkspace.SecurityData.SaveChanges()

' Iterate through all Roles
For Each role As Role In Me.DataWorkspace.SecurityData.Roles
Next

' Find a specific role
Dim role As Role = Me.DataWorkspace.SecurityData.Roles_Single("Manager")

 

RoleAssignment

The RoleAssignment entity represents a mapping between a Role and a UserRegistration.  It is how you define that a user belongs to a role.

Here is some example code using the RoleAssignment entity:

C#

// Assign Kim to the Manager role
UserRegistration user = this.DataWorkspace.SecurityData.UserRegistrations_Single("contoso\\kim");
Role role = this.DataWorkspace.SecurityData.Roles_Single("Manager");
RoleAssignment roleAssignment = user.RoleAssignments.AddNew();
roleAssignment.Role = role;
this.DataWorkspace.SecurityData.SaveChanges();

// Find which roles Kim is assigned to
UserRegistration user = this.DataWorkspace.SecurityData.UserRegistrations_Single("contoso\\kim");
foreach (RoleAssignment roleAssignment in user.RoleAssignments)
{
Role role = roleAssignment.Role;
}

VB:

' Assign Kim to the Manager role
Dim user As UserRegistration = Me.DataWorkspace.SecurityData.UserRegistrations_Single("contoso\\kim")
Dim role As Role = Me.DataWorkspace.SecurityData.Roles_Single("Manager")
Dim roleAssignment As RoleAssignment = user.RoleAssignments.AddNew()
roleAssignment.Role = role
Me.DataWorkspace.SecurityData.SaveChanges()

' Find which roles Kim is assigned to
Dim user As UserRegistration = Me.DataWorkspace.SecurityData.UserRegistrations_Single("contoso\\kim")
For Each roleAssignment As RoleAssignment In user.RoleAssignments
Dim role As Role = roleAssignment.Role
Next

 

Permission

The Permission entity represents an action that a logged in user is permitted to do within the application.  Examples of permissions in an application include “CanRejectSalesOrder” and “CanUpdateInventory”.  Permissions are different than the rest of the security data because they are read-only.  The permissions that are available map to the permissions that were defined within the Access Control tab of the application properties of a LightSwitch project:

image 

Here is some example code using the Permission entity:

C#:

// Iterate through all Permissions
foreach (Permission permission in this.DataWorkspace.SecurityData.Permissions)
{
}

// Find a specific Permission
Permission permission = this.DataWorkspace.SecurityData.Permissions_Single(Permissions.CanRejectSalesOrder);

VB:

' Iterate through all Permissions
For Each permission As Permission In Me.DataWorkspace.SecurityData.Permissions
Next

' Find a specific Permission
Dim permission As Permission = Me.DataWorkspace.SecurityData.Permissions_Single(Permissions.CanRejectSalesOrder)

 

RolePermission

The RolePermission entity represents a mapping between a Role and a Permission.  It is how you define that a permission is assigned to a role.

Here is some example code using the RolePermission entity:

C#:

// Assign CanRejectSalesOrder permission to Manager role
Role role = this.DataWorkspace.SecurityData.Roles_Single("Manager");
Permission permission = this.DataWorkspace.SecurityData.Permissions_Single(Permissions.CanRejectSalesOrder);
RolePermission rolePermission = role.RolePermissions.AddNew();
rolePermission.Permission = permission;
this.DataWorkspace.SecurityData.SaveChanges();

// Find which permissions are assigned to the Manager role
Role role = this.DataWorkspace.SecurityData.Roles_Single("Manager");
foreach (RolePermission rolePermission in role.RolePermissions)
{
Permission permission = rolePermission.Permission;
}

VB:

' Assign CanRejectSalesOrder permission to Manager role
Dim role As Role = Me.DataWorkspace.SecurityData.Roles_Single("Manager")
Dim permission As Permission = Me.DataWorkspace.SecurityData.Permissions_Single(Permissions.CanRejectSalesOrder)
Dim rolePermission As RolePermission = role.RolePermissions.AddNew()
rolePermission.Permission = permission
Me.DataWorkspace.SecurityData.SaveChanges()

' Find which permissions are assigned to the Manager role
Dim role As Role = Me.DataWorkspace.SecurityData.Roles_Single("Manager")
For Each rolePermission As RolePermission In role.RolePermissions
Dim permission As Permission = rolePermission.Permission
Next

 

Conclusion

Using the SecurityData service and the entities it exposes, you can accomplish all kinds of interesting scenarios that require dynamic management of your application’s security data.  I hope you’ve found this blog post helpful in your work.  Happy coding.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 21 Feb 2012 14:37

The Problem:

The other day I published an updated version of my Windows Phone app CalcuFitness after some major code refactoring.  Much to my surprise, I discovered that the app certification process determined that my app required the location services capability when it in fact does not make use of location services.  It wasn’t long before I realized what caused this.

I have several Windows Phone apps in development and, being a good developer, I try to share as much code between them as I can.  So I create common library projects that many of my apps reference.  Well, one of my apps did need to use location service functionality and I decided to put some of that functionality into one of the common libraries because it was general purpose enough to be used by other apps.  Well, my CalcuFitness app referenced that library and compiled that code into its binary.

When you submit your app to the Marketplace, they automatically scan your binary looking to see whether you use certain APIs to determine what app capabilities are required.  Since my app’s binary contained code that referenced an API associated with location services, the system marked my app as requiring that capability.  It doesn’t matter whether there’s a code path in my app that actually makes use of that API.

The Solution:

The way I went about solving this problem was to make use of conditional symbols and build configurations in Visual Studio to control the code that actually gets compiled for my phone app.  First, I define a conditional symbol for each of the capabilities that my code makes use of and wrap that code within #if…#endif preprocessing directives.  In my case, I created a LOCATION_SERVICE_CAPABILITY symbol and added it to my code like this:

#if LOCATION_SERVICE_CAPABILITY
// my location service code
#endif

Ok, so now this code will only be compiled if the project is built with the LOCATION_SERVICE_CAPABILITY symbol.  By default, my app will not compile this code since it’s not configured to have the LOCATION_SERVICE_CAPABILITY symbol defined.

Now let’s say that I have another app – let’s call it “MyLocationPhoneApp” – where I do want this location service functionality to be used.  I can’t just set the LOCATION_SERVICE_CAPABILITY symbol for the Debug and Retail build configurations because that would cause this code to be compiled into all my phone apps that reference this project.  Instead, I’m going to create a specific build configuration for my app.  To do this, I do the following:

  1. Open the project file of my library.
  2. Create a new build configuration by copying the Debug and/or Release configuration.
  3. Change the name of this new configuration by including the name of the phone app which references this library.
  4. Include additional symbol names in the DefineConstants that correlate to the symbols defined in the library that are used by the app.

For example, here’s the Debug configuration I created with the important parts highlighted:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'MyLocationPhoneApp_Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>Bin\Debug</OutputPath>
<DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE;LOCATION_SERVICE_CAPABILITY</DefineConstants>
</PropertyGroup>

I actually do this for both Debug and Release to ensure that I can build with the constant in either mode. Whenever this project is built using this build configuration, the location service-related code will be included in the compilation.  Ok, that’s good but I’m not done yet.

Next I need to open up Configuration Manager (Build –> Configuration Manager) in Visual Studio.  This window allows me to define which build configuration to use for each of the projects in my solution.  So when my solution is configured to build Debug, I configure my library project to build with the “MyLocationPhoneApp_Debug” configuration.

And I follow this pattern for each app that references this library project.  Essentially, the build configuration let’s me create an app profile that defines which capabilities should be exposed by the library.  This prevents code which impacts the phone capability requirements from entering into my app’s binary if it doesn’t require that capability.

Author: "Matt Thalman" Tags: "Windows Phone"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 15 Feb 2012 20:42

In the LightSwitch apps that I create, I have a common pattern where I display a “Loading” message in the title bar of a screen while it is loading and then set it to its actual screen name once it’s finished.  In particular, this is useful for screens whose title is dependent on the data that is loaded by the screen, such as a customer detail screen whose title is the name of the customer.

This is just a nice little tweak to the UI that’s quite simple to implement.  Here’s how:

Ensure that focus is set to your screen’s content tree and choose the InitializeDataWorkspace event from the Write Code dropdown button:

image

In the method stub that gets generated, add the following code (replacing CustomerDetail with your actual screen name):

C#:

partial void CustomerDetail_InitializeDataWorkspace(
List<IDataService> saveChangesTo) { this.DisplayName = "Loading..."; }

VB:

Private Sub CustomerDetail_InitializeDataWorkspace(saveChangesTo _
As System.Collections.Generic.List(Of Microsoft.LightSwitch.IDataService)) Me.DisplayName = "Loading..." End Sub

 

And that’s all you have to do if you are using a Details screen template.  That’s because for a Details screen, LightSwitch automatically generates code for the entity property’s Loaded event to update the display name based on the entity’s data.

The InitializeDataWorkspace event is used because that’s the very first event that the screen raises.  So within that event, the screen’s display name is immediately set to “Loading…”.  Then, once the data is loaded, code runs in the Loaded event that explicitly sets the screen’s display name to the desired value.

If you wanted to apply this technique to a non-Details screen, you would do the same thing as above but additionally you would need to implement the Loaded event for one of your screen’s entity or collection properties that would set the DisplayName of the screen.  For example, here’s how I’ve done it for my Customers Grid screen:

image

C#:

partial void Customers_Loaded(bool succeeded)
{
    this.DisplayName = "Customers";
}

VB:

Private Sub Customers_Loaded(succeeded As Boolean)
    Me.DisplayName = "Customers"
End Sub

 

The end result is that you see this while the screen is loading:

image

and this once it’s finished loading:

image

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch"
Comments Send by mail Print  Save  Delicious 
Date: Thursday, 08 Dec 2011 14:06

When configuring a Visual Studio LightSwitch application to use Forms authentication, the application user is prompted with the following login UI when they open the application:

original-login

Many LightSwitch customers have asked about creating their own custom UI in place of this default login experience.  Maybe you’d like to display the company logo, for example.  This post will show you the steps for creating your own fully customizable login page.

LightSwitch doesn’t have not have built-in support for customizing this UI.  However, since LightSwitch is an ASP-NET based application you can use the features in ASP.NET to workaround this.  What I’m going to demonstrate here is how to create an ASPX page that will authenticate the user when they open the app.  Since you write the content of the ASPX page, you get to control exactly how it looks to the user.  But I’ll make it easy for you by providing some sample markup that you can use and customize.

NOTE:
These instructions are for creating a custom login page for Web-based LightSwitch applications (meaning, the application is hosted within the browser).  There isn’t a way to create a custom login page for a Desktop LightSwitch application.  In addition, these instructions assume that you have Visual Studio Professional or higher installed in addition to LightSwitch.  This isn’t necessarily required, but it makes the task of adding ASPX files to the project simpler; otherwise, you’d have to do this by hand which I won’t be describing in this post.

First, let’s start with a brand new LightSwitch project and open up the application properties window:

open-app-properties

In the application properties window, select the Access Control tab and enable Forms authentication:

enable-forms-auth

Select the Application Type tab and change the client type to Web:

web-app-type

Now switch Solution Explorer into File View in order to manage the physical files that make up a LightSwitch application:

switch-to-file-view 

Next, click the “Show All Files” toolbar button.  This shows all the hidden files within the project.

show-all-files

This is what the resulting project looks like now:

expanded-project

Add a new ASPX page to the ServerGenerated project by selecting the ServerGenerated project and hit Ctrl+Shift+A.  Then select “Web Form” from the Web node and change the filename to “Home.aspx”.  Click the Add button. 

add-login-page

Follow the same steps again to add another ASPX file but name this one “Login.aspx”.  You should now have two ASPX files in your ServerGenerated project:

home-and-login

Open Login.aspx and paste over the existing markup with the following:

C#:

<%@ Page Title="Log In" Language="C#" AutoEventWireup="true"
    CodeBehind="Login.aspx.cs" Inherits="LightSwitchApplication.Login" %>

<form id="Form1" runat="server">
  <div style="text-align:center">
   <!— Add an optional image by replacing this fake image URL with your own –>
   <!--<asp:Image runat="server" ImageUrl="http://contoso.com/logo.gif" />-->
   <asp:Login runat="server" BackColor="#F7F6F3"
           BorderColor="#E6E2D8" BorderPadding="4"
           BorderStyle="Solid" BorderWidth="1px"
           Font-Names="Verdana" Font-Size="0.8em"
           ForeColor="#333333">
       <InstructionTextStyle Font-Italic="True" ForeColor="Black" />
       <LoginButtonStyle BackColor="#FFFBFF" BorderColor="#CCCCCC"
           BorderStyle="Solid" BorderWidth="1px" Font-Names="Verdana"
           Font-Size="0.8em" ForeColor="#284775" />
       <TextBoxStyle Font-Size="0.8em" />
       <TitleTextStyle BackColor="#5D7B9D" Font-Bold="True"
           Font-Size="0.9em" ForeColor="White" />
   </asp:Login>
 </div>
</form>

VB:

<%@ Page Title="Log In" Language="vb" AutoEventWireup="true"
    CodeBehind="Login.aspx.vb" Inherits=".Login" %>

<form id="Form1" runat="server">
  <div style="text-align:center">
   <!— Add an optional image by replacing this fake image URL with your own –>
   <!--<asp:Image runat="server" ImageUrl="http://contoso.com/logo.gif" />-->
   <asp:Login runat="server" BackColor="#F7F6F3"
           BorderColor="#E6E2D8" BorderPadding="4"
           BorderStyle="Solid" BorderWidth="1px"
           Font-Names="Verdana" Font-Size="0.8em"
           ForeColor="#333333">
       <InstructionTextStyle Font-Italic="True" ForeColor="Black" />
       <LoginButtonStyle BackColor="#FFFBFF" BorderColor="#CCCCCC"
           BorderStyle="Solid" BorderWidth="1px" Font-Names="Verdana"
           Font-Size="0.8em" ForeColor="#284775" />
       <TextBoxStyle Font-Size="0.8em" />
       <TitleTextStyle BackColor="#5D7B9D" Font-Bold="True"
           Font-Size="0.9em" ForeColor="White" />
   </asp:Login>
 </div>
</form>

For more details on how to customize the Login control to suit your needs, see the following MSDN article: Customizing the Appearance of ASP.NET Login Controls.

For the Home.aspx page, you can leave the default markup code since this page will never be visible by the user.  We’re only going to use it as a redirection mechanism.

NOTE:
This redirection logic is only needed to workaround an issue in LightSwitch V1 where it will remove from the web.config file at publish-time a configuration setting that will deny anonymous users access.   If you have the ability to modify your web.config file after the app has been published, you can configure it to deny anonymous users by adding the following to the system.web section of the web.config file:

<authorization>
  <deny users="?"/>
</authorization>

If you end up doing this, the Home page described in this blog post would not be necessary within your site.

To setup the redirection logic, open up the code-behind for the Home page, Home.aspx.cs, and replace its contents with the following code:

C#:

using System;
using System.Web.Security;

namespace LightSwitchApplication
{
    public partial class Home : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!this.User.Identity.IsAuthenticated)
            {
                FormsAuthentication.RedirectToLoginPage();
            }
            else
            {
                this.Response.Redirect(FormsAuthentication.DefaultUrl);
            }
        }
    }
}

VB:

Imports System.Web.Security

Public Class Home
    Inherits System.Web.UI.Page



Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles Me.Load If Not Me.User.Identity.IsAuthenticated Then FormsAuthentication.RedirectToLoginPage() Else Me.Response.Redirect(FormsAuthentication.DefaultUrl) End If End Sub
End Class

Next, we need to configure the default page for the site to use this new Home page.  Open the web.config file contained in the ServerGenerated folder.  It will have a section that looks like this:

<defaultDocument>
  <files>
    <clear />
    <add value="default.htm" />
  </files>
</defaultDocument>

To configure the new default page, change “default.htm” to “Home.aspx”.

In addition, we need to configure default.htm to be the page that is redirected to after a successful login.  To do this, find the forms element in the web.config file and add the bolded text:

<authentication mode="Forms">
  <forms name="CustomLoginApp" defaultUrl="default.htm" />
</authentication>

The last step is to configure the main LightSwitch project to be aware of the new ASPX files that were added so that they will be published along with the app. To do this, unload the main LightSwitch project:

unload-project

With the project unloaded, open the physical .LSPROJ file in the IDE:

edit-unloaded-project

Do a search for “_BuildFile” and append the following text within that section of the file:

<_BuildFile Include="ServerGenerated\Login.aspx">
  <SubFolder>
  </SubFolder>
  <PublishType>
  </PublishType>
</_BuildFile>
<_BuildFile Include="ServerGenerated\Home.aspx"> <SubFolder> </SubFolder> <PublishType> </PublishType> </_BuildFile>

Reload the LightSwitch project:

reload-project

Your LightSwitch app is now configured to use your new custom Login page.  When you publish your app and connect to it, you’ll be redirected to your login page.  After successfully logging in, you’ll be redirected to the LightSwitch app.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 31 Oct 2011 17:54

Think you’ve got what it takes to be a LightSwitch star?  Check out the new LightSwitch application contest at http://www.codeproject.com/Competitions/524/LightSwitch-Star-Contest.aspx.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 26 Jul 2011 17:00

Today is an exciting day.  After years of hard work, Visual Studio LightSwitch V1 has been released.  This is my first shipped product while working in the Server & Tools Division at Microsoft and I couldn’t be happier (my previous shipped products were in the Business Division).  Feedback from the first two beta versions has been very positive and we are all excited to have reached this milestone.  There seems to be a lot of buzz in the community.

We can all admit that LightSwitch V1 is not a perfect product.  It has its quirks and is missing some features that people would like to see.  It is a V1 after all.  But even so, it’s amazing what this product can do for your app building productivity.  When I sit down to write an app, I no longer have to ask myself these questions: how am I going to read and write data from the database, how am I going to handle communication between the client and server, how am I going to make the UI functional and look good, how am I going to write the plumbing for authentication.  LightSwitch answers these questions for me so I don’t have to worry about them.  I can concentrate on making the app, not the guts.

As productive as LightSwitch V1 lets you become today, there’s still more it can do.  This isn’t the last version of LightSwitch you’re going to see.  Stay tuned for more LightSwitch awesomeness in the future.

Happy coding LightSwitching,

Matt

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 12 Apr 2011 19:41

Visual Studio LightSwitch makes use of .NET portable assemblies to allow developers to write business logic that can be executed on both the client (Silverlight) and server (.NET 4) tiers.  In LightSwitch terminology, we refer to the assembly that contains this shared logic as the Common assembly.  In this post, I’m going to describe a coding pattern that allows you to invoke code from the Common assembly that has different implementations depending on which tier the code is running on.

In my scenario, I have a Product entity which has an Image property and the image must be a specific dimension (200 x 200 pixels).  I would like to write validation code for the Image property to ensure that the image is indeed 200 x 200.  But since the validation code for the Image property is contained within the Common assembly, I do not have access to the image processing APIs that allow me to determine the image dimensions.

This problem can be solved by creating two tier-specific implementations of the image processing logic and store that in classes which derive from a common base class that is defined in the Common assembly.  During the initialization of the client and server applications, an instance of the tier-specific class is created and set as a static member available from the Common assembly.  The validation code in the Common assembly can now reference that base class to invoke the logic.  I realize that may sound confusing so let’s take a look at how I would actually implement this.

This is the definition of my Product entity:

1

I now need to add some of my own class files to the LightSwitch project.  To do that, I switch the project to File View.

2

From the File View, I add a CodeBroker class to the Common project.

3

The CodeBroker class is intended to be the API to tier-specific logic.  Any code in the Common assembly that needs to execute logic which varies depending on which tier it is running in can use the CodeBroker class. Here is the implementation of CodeBroker:

C#:

public abstract class CodeBroker
{
    private static CodeBroker current;

    public static CodeBroker Current
    {
        get { return CodeBroker.current; }
        set { CodeBroker.current = value; }
    }

    public abstract void GetPixelWidthAndHeight(byte[] image, out int width,
out int height); }

VB:

Public MustInherit Class CodeBroker
    Private Shared m_current As CodeBroker

    Public Shared Property Current() As CodeBroker
        Get
            Return CodeBroker.m_current
        End Get
        Set(value As CodeBroker)
            CodeBroker.m_current = value
        End Set
    End Property

    Public MustOverride Sub GetPixelWidthAndHeight(image As Byte(),
ByRef width As Integer,
ByRef height As Integer) End Class

I next add a ClientCodeBroker class to the Client project in the same way as I added the CodeBroker class to the Common project.  Here’s the implementation of ClientCodeBroker:

C#:

using Microsoft.LightSwitch.Threading;

namespace LightSwitchApplication
{
    public class ClientCodeBroker : CodeBroker
    {
        public override void GetPixelWidthAndHeight(byte[] image, out int width,
out int height) { int bitmapWidth = 0; int bitmapHeight = 0; Dispatchers.Main.Invoke(() => { var bitmap = new System.Windows.Media.Imaging.BitmapImage(); bitmap.SetSource(new System.IO.MemoryStream(image)); bitmapWidth = bitmap.PixelWidth; bitmapHeight = bitmap.PixelHeight; }); width = bitmapWidth; height = bitmapHeight; } } }

VB:

Imports Microsoft.LightSwitch.Threading

Namespace LightSwitchApplication
    Public Class ClientCodeBroker
        Inherits CodeBroker
        Public Overrides Sub GetPixelWidthAndHeight(image As Byte(),
ByRef width As Integer, ByRef height As Integer) Dim bitmapWidth As Integer = 0 Dim bitmapHeight As Integer = 0 Dispatchers.Main.Invoke( Sub() Dim bitmap = New Windows.Media.Imaging.BitmapImage() bitmap.SetSource(New System.IO.MemoryStream(image)) bitmapWidth = bitmap.PixelWidth bitmapHeight = bitmap.PixelHeight End Sub) width = bitmapWidth height = bitmapHeight End Sub End Class End Namespace

(By default, my application always invokes this GetPixelWidthAndHeight method from the Logic dispatcher.  So the call to invoke the logic on the Main dispatcher is necessary because BitmapImage objects can only be created on the Main dispatcher.)

To include the server-side implementation, I add a ServerCodeBroker class to the Server project.  It’s also necessary to add the following assembly references in the Server project because of dependencies in my image code implementation: PresentationCore, WindowsBase, and System.Xaml.  Here is the implementation of ServerCodeBroker:

C#:

public class ServerCodeBroker : CodeBroker
{
    public override void GetPixelWidthAndHeight(byte[] image, out int width,
out int height) { var bitmap = new System.Windows.Media.Imaging.BitmapImage(); bitmap.BeginInit(); bitmap.StreamSource = new System.IO.MemoryStream(image); bitmap.EndInit(); width = bitmap.PixelWidth; height = bitmap.PixelHeight; } }

VB:

Public Class ServerCodeBroker
    Inherits CodeBroker
    Public Overrides Sub GetPixelWidthAndHeight(image As Byte(),
ByRef width As Integer, ByRef height As Integer) Dim bitmap = New System.Windows.Media.Imaging.BitmapImage() bitmap.BeginInit() bitmap.StreamSource = New System.IO.MemoryStream(image) bitmap.EndInit() width = bitmap.PixelWidth height = bitmap.PixelHeight End Sub End Class

The next thing is to write the code that instantiates these broker classes.  This is done in the Application_Initialize method for both the client and server Application classes.  For the client Application code, I switch my project back to Logical View and choose “View Application Code (Client)” from the right-click context menu of the project.

4

In the generated code file, I then add the following initialization code:

C#:

public partial class Application
{
    partial void Application_Initialize()
    {
        CodeBroker.Current = new ClientCodeBroker();
    }
}

VB:

Public Class Application
    Private Sub Application_Initialize()
        CodeBroker.Current = New ClientCodeBroker()
    End Sub
End Class

This initializes the CodeBroker instance for the client tier when the client application starts.

I need to do the same thing for the server tier.  There is no context menu item available for editing the server application code but the code file can be added manually.  To do this, I switch my project back to File View and add an Application class to the Server project.

5

The implementation of this class is very similar to the client application class.  Since the server’s Application_Initialize method is invoked for each client request, I need to check whether the CodeBroker.Current property has already been set from a previous invocation.  Since the CodeBroker.Current property is static, its state remains in memory across multiple client requests.

C#:

public partial class Application
{
    partial void Application_Initialize()
    {
        if (CodeBroker.Current == null)
        {
            CodeBroker.Current = new ServerCodeBroker();
        }
    }
}

VB:

Public Class Application
    Private Sub Application_Initialize()
        If CodeBroker.Current Is Nothing Then
            CodeBroker.Current = New ServerCodeBroker()
        End If
    End Sub
End Class

The next step is to finally add my Image property validation code.  To do this, I switch my project back to Logical View, open my Product entity, select my Image property in the designer, and choose “Image_Validate” from the Write Code drop-down button.

6

In the generated code file, I add this validation code:

C#:

public partial class Product
{
    partial void Image_Validate(EntityValidationResultsBuilder results)
    {
        if (this.Image == null)
        {
            return;
        }

        int width;
        int height;
        CodeBroker.Current.GetPixelWidthAndHeight(this.Image, out width,
out height); if (width != 200 && height != 200) { results.AddPropertyError(
"Image dimensions must be 200x200.",
this.Details.Properties.Image); } } }

VB:

Public Class Product
    Private Sub Image_Validate(results As EntityValidationResultsBuilder)
        If Me.Image Is Nothing Then
            Return
        End If

Dim
width As Integer Dim height As Integer CodeBroker.Current.GetPixelWidthAndHeight(Me.Image, width, height) If width <> 200 AndAlso height <> 200 Then results.AddPropertyError("Image dimensions must be 200x200.",
Me.Details.Properties.Image) End If End Sub End Class

This code can execute on both the client and the server.  When running on the client, CodeBroker.Current will return the ClientCodeBroker instance and provide the client-specific implementation for this logic.  And when running on the server, CodeBroker.Current will return the ServerCodeBroker instance and provide the server-specific implementation.

And there you have it.  This pattern allows you to write code that is invoked from the Common assembly but needs to vary depending on which tier is executing the logic.  I hope this helps you out in your LightSwitch development.

Author: "Matt Thalman"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 15 Mar 2011 19:32

I’m very excited to say that we’ve released Beta 2 of Visual Studio LightSwitch to MSDN subscribers.  It will be available publicly on Thursday, Mar. 17.  So go out there and start downloading.  Let us know what you think.

Author: "Matt Thalman"
Comments Send by mail Print  Save  Delicious 
Date: Thursday, 21 Oct 2010 18:56

One of the features available in Visual Studio LightSwitch is to model queries that can be reused in other queries that you model.  This allows developers to write a potentially complex query once and be able to define other queries which reuse that logic.  In V1 of LightSwitch, this query reuse is exposed through the concept of a query source.

All queries that you create have a source.  The source of a query defines the set of entities on which the query will operate.  By default, any new query that you create will have its source set to the entity set of the table for which you created the query.  So if I create a query for my Products table, the source of the query will be the Products entity set.  You can think of the entity set as being similar to a SELECT * FROM TABLE for the table.  The entity set is always the root; it does not have a source.  Developers have the ability to change a query’s source.  The source of a query can be set to another query that has already been defined.  (You can do this as long as both queries are returning the same entity type.  You can’t, for example, define a query for customers and a query for products and define the source of the products query to be the customer query.)  This effectively creates a query chain where the results of one query are fed to the next query where the results are further restricted.

To illustrate how this works, let’s start with a sample set of Product data to work with:

Name Category DiscontinuedDate UnitsInStock
Chai Beverages 10/10/2010 6
Chef Anton's Cajun Seasoning Condiments <NULL> 54
Guarana Fantastica Beverages <NULL> 62

I’ve defined a query named ProductsByCategory that returns the products of a given category:

ProductsByCategory

This query will return the following data when “Beverages” is passed as the Category parameter:

Name Category DiscontinuedDate UnitsInStock
Chai Beverages 10/10/2010 6
Guarana Fantastica Beverages <NULL> 62

Now this query can be reused for any other query which wants to retrieve data for a specific category but also wants to further refine the results.  In this case, I’ll define a query named DiscontinuedProducts that returns all discontinued products for a given category.

DiscontinuedProducts

Notice the red bounding box which I’ve added to indicate that this query’s source is set to the ProductsByCategory query.  You’ll also notice that this query “inherits” the Category parameter from its source query.  This allows the DiscontinuedProducts query to consume that parameter in its filter should it need to do so.  The result of this query is the following:

Name Category DiscontinuedDate UnitsInStock
Chai Beverages 10/10/2010 6

It may be helpful to think of object inheritance in the context of query sources.  In other words, the DiscontinuedProducts query inherits the logic of ProductsByCategory and extends that logic with its own. 

It should be noted that any sorts that are defined for queries are only applicable for the query that is actually being executed.  So if ProductsByCategory sorted its products by name in descending order and DiscontinuedProducts sorted its products by name in ascending order, then the results of the DiscontinuedProducts query will be in ascending order.  In other words, the sorting defined within base queries are ignored.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 20 Sep 2010 20:14

In Visual Studio LightSwitch, there are a set of security entities defined by the runtime such as UserRegistration, Role, and Permission.  Numerous people have asked how they can create relationships to these entities.  These entities can’t be referenced within a developer’s application model.  They are only available programmatically.  There are potentially multiple solutions for working around this limitation.  The following is a solution that makes use of LightSwitch’s support for custom WCF RIA Services.

This solution involves defining a custom WCF RIA Service that exposes proxy entities that delegate to the underlying LightSwitch SecurityDataService (the data service that provides programmatic access to the security data).  For purposes of brevity, this solution will only expose read access to the Role data.

The first task is to create an assembly that will host the WCF RIA Service.  To do this, create a new project using the “Windows\Class Library” template.

The project needs to have access to the SecurityData API so a reference to the Microsoft.LightSwitch.dll assembly will need to be added.  This assembly can be located at “%ProgramFiles%\Microsoft Visual Studio 10.0\Common7\IDE\LightSwitch\1.0\Client\Microsoft.LightSwitch.dll”.  Part of this implementation will need to work with transactions, so an assembly reference to System.Transactions.dll needs to be added to this project as well.

Next, the proxy entity for Role needs to be defined.  This entity should contain properties to expose whatever data you’d like from the underlying system security entities.  In this case, the Role entity just has a Name property.  Define a new class with the following code:

public class Role
{
    [Key]
    [ReadOnly(true)]
    public string Name { get; set; }
}

WCF RIA Services exposes data through a DomainService class.  To create this class, open the Add New Item dialog for the project and select the “Web\Domain Service Class” template.

Add New Item dialog


In the dialog that opens, choose a name for the service (e.g. ProxySecurityDataService) and uncheck the “Enable client access” checkbox.  This ensures that the service won’t be exposed as general-purpose web service so only your LightSwitch app will have access to it.

Add New Domain Service dialog


To expose the role data, a GetRoles query method is defined on the domain service as shown below:

using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.DomainServices.Server;
using System.Transactions;
using Microsoft.LightSwitch;
using Microsoft.LightSwitch.Framework.Base;

public class ProxySecurityDataService : DomainService
{
    [Query(IsDefault = true)]
    public IEnumerable<Role> GetRoles()
    {
        Transaction currentTrx = Transaction.Current;
        Transaction.Current = null;
        try
        {
            IDataWorkspace workspace =
ApplicationProvider.Current.CreateDataWorkspace(); IEnumerable<Microsoft.LightSwitch.Security.Role> roles =
workspace.SecurityData.Roles.GetQuery().Execute(); return roles.Select(r => new Role { Name = r.Name }); } finally { Transaction.Current = currentTrx; } } }

One note about this implementation:

The current transaction is set to null during the execution of the query for roles.  This is necessary to avoid the need for a distributed transaction.  By default, the LightSwitch runtime creates a transaction before invoking this custom domain service to ensure that data is accessed with a ReadCommitted isolation level.  If we left that transaction set as the current transaction then the query for roles would result in an exception if the MSDTC service was not running because it would detect an attempt for a distributed transaction.  However, since the implementation of this domain service is simply acting as a proxy and not doing any data access of its own, it’s safe to set that transaction to null.  This ensures that when the role query on SecurityDataService executes, there is not an existing transaction so there is no issue of a distributed transaction attempt.

This is all that needs to be done for the implementation of the WCF RIA Service.  Now just compile this project and let’s move on.

At this point, we’re ready to move to the LightSwitch application itself.  From the LightSwitch app, a reference to the WCF RIA Service is made by right-clicking the Data Sources node in the Solution Explorer and selecting “Add Data Source”.  In this wizard, choose WCF RIA Service and click Next to continue.

Attach Data Source wizard


In the next wizard step, add a reference to the assembly you created previously that hosts the WCF RIA Service.

Choose WCF RIA Service

In the last wizard step, check the Entities box to indicate that all the entities defined in the WCF RIA Service should be imported.

Choose Data Source Objects


Now the Role proxy entity is exposed in the application model and can be referenced just like any other entity.  For example, you could create a screen that exposes the list of roles that are defined. 

For more information on how to implement custom WCF RIA Services consumable by LightSwitch, check out the Visual Studio LightSwitch Beta 2 Training Kit.  It includes a section on LightSwitch Data Source Extensions.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch, Security"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 07 Sep 2010 14:56

In many applications, you need to filter data that is only relevant to the particular user that is logged in.  For example, a personal information manager application may only want users to view their own tasks and not the tasks of other users.  Here’s a walkthrough of how you can setup this kind of data filtering in Visual Studio LightSwitch.

I’ll first create a Task table which has two fields: one for the task description and another to store the user name of the user who created the task.



Next, I’ll need to write some code so that whenever a Task is created, it will automatically have it’s CreatedBy field set to the current user.  To do this, I can use Write Code drop-down on the table designer to select the Created method.



Here’s the code:

partial void Task_Created()
{
    this.CreatedBy = this.Application.User.Name;
}

Now we’re at the data filtering step.  What I’d really like to do is have all queries for Tasks be filtered according to the current user.  So even if I model a new query for Tasks then it will automatically get this filtering behavior.  That way I only have to write this code once and it will be applied whenever tasks are queried.  LightSwitch provides a built-in query for each table that returns all instances within that table.  The name of this query is TableName_All.  All other queries for that table are based on that All query.  So if I can modify the behavior of that All query, then every other query that queries the same table will also get that behavior.  LightSwitch just so happens to provide a way to modify the default behavior of the All query.  This can be done through the PreprocessQuery method.  This method is also available through the Write Code drop-down. 



The PreprocessQuery method allows developers to modify the query before it is executed.  In my case, I want to add a restriction to it so that only tasks created by the current user are returned.

partial void Tasks_All_PreprocessQuery(ref IQueryable<LightSwitchApplication.Task> query)
{
    query = query.Where(t => t.CreatedBy == this.Application.User.Name);
}

And that’s all I need to do.  Now, whenever any query is made for tasks it will add this restriction.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch, Security"
Comments Send by mail Print  Save  Delicious 
Date: Thursday, 02 Sep 2010 17:50

Securing your Visual Studio LightSwitch application begins with defining permissions.  In the first version of LightSwitch, developers are responsible for defining and consuming their own permissions.  Once permissions have been defined, you can write the business logic to consume them where appropriate.  As part of the development process, only permissions and their associated logic need to be defined.  Once the application has been published, it can be administered to add users and roles and assign permissions.

The following is a walkthrough showing what is involved in this process:

To start with, I’ve created a simple Customer table:



In this application, I want to secure the ability to delete customers.  To do this, I need to create a new permission.  Permissions can be defined in the Access Control tab of the application properties.  To get to the application properties you can double-click the Properties node in Solution Explorer or right-click the Application node and select Properties.  Before permissions can be added, you need to enable authentication by choosing whether to use Windows or Forms authentication (see my previous blog post for more info on this).  For my purpose, I’ve chosen to use Forms authentication.  Now that authentication is enabled, I can add permissions.  I’ve defined a permission named CanDeleteCustomer that provides the ability for users to delete customers:



With the permission defined, I can now write some code to secure the customer table.  To do this, I navigate back to the Customer table and select “Customers_CanDelete” from the Write Code drop-down button:



This opens up the code file for the customer table and generates the method stub where I can write my logic. 

partial void Customers_CanDelete(ref bool result)
{
    result = this.Application.User.HasPermission(
Permissions.CanDeleteCustomer); }

A few things to note about this code:

  • The result parameter is assigned a value that indicates whether the user can delete the customer.
  • The User object is accessible from the Application class.  The User object provides all sorts of information about the current user, most notably whether they have a specific permission.
  • The Permissions class is a generated class that contains the permissions that were defined in the Access Control tab.
  • This code runs on the server not the client.  This ensures that the customer table will always be protected from a client that may not enforce this permission.

Ok, let’s test this to ensure it’s behaving as expected.  First, I create an editable grid screen for the customer table.  Now I’ll run the app and see how it looks.



Here you’ll see that the Delete button is disabled.  By default, the currently running user doesn’t have the CanDeleteCustomer permission and the UI for the grid is reflecting this.  So now you may be wondering how we can run as a user that does have that permission.  To do that, I can just go back to the Access Control tab and check the “Granted for debug” checkbox for the CanDeleteCustomer permission.



Now when I run the app, the Delete button is enabled.



In a subsequent blog post, I’ll describe how you assign permissions in a published application.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch, Security"
Comments Send by mail Print  Save  Delicious 
Date: Thursday, 26 Aug 2010 21:04

Visual Studio LightSwitch provides screen templates for defining a details screen or a new data screen for an entity.  But you may want to use the same screen for doing both tasks.  This allows you to have a consistent experience no matter whether you are creating an entity or simply editing an existing one.  Here’s how you can do this.

  1. Create an entity to work with.  For the purposes of this tutorial, I’ve created a Customers table.
  2. Create a Details Screen for Customer: 
  3. Rename the Customer property on the screen to CustomerQuery: 
  4. Select the CustomerID property and make it optional by unchecking its "Is Required" property in the property sheet:


  5. Click the “Add Data Item…” button in the command bar and create a local Customer property: 
  6. Delete the current content on the screen bound to the CustomerQuery.  We want to replace the content in the screen to be bound to the Customer property, not the CustomerQuery. 
  7. In its place, we want to bind the Customer property onto the screen: 
  8. Change the control type of the Customer to be a Rows Layout.  By default, this will add controls for each of the fields defined in Customer which is exactly what we want. 
  9. Now we need to write some code to hook everything up.  Click the Write Code button on the command bar at the top of the screen designer.  Paste the following code into the generated class, replacing the pre-existing implementations of the Loaded, Changed, and Saved methods:

    partial void CustomerQuery_Loaded(bool succeeded)
    {
        if (!this.CustomerId.HasValue)
        {
            this.Customer = new Customer();
        }
        else
        {
            this.Customer = this.CustomerQuery;
        }

        this.SetDisplayNameFromEntity(this.Customer);
    }

    partial void CustomerQuery_Changed()
    {
        this.SetDisplayNameFromEntity(this.Customer);
    }

    partial void CustomerDetail_Saved()
    {
        this.SetDisplayNameFromEntity(this.Customer);
    }

    So what happens here is that the screen has a parameter called CustomerId which represents the ID of the Customer.  If that property is not set, we assume the screen should create and display a new customer.  If that property is set, we simply set the Customer property to the return value of the CustomerQuery query which is actually bound to the CustomerId property (the screen template did that work for us).  Notice that we’re setting the Customer property here because that is what all of the screen content is bound to.  So by setting this property, it updates the controls on the screen with the state from that entity.
  10. Ok, how do we use this screen?  Well, by default any customer displayed as Summary control defined as a link will automatically navigate to this screen.  If you want to navigate to this screen through the use of a List, for example, just following the next set of steps.
  11. Create a List and Details Screen for Customers: 
  12. Expand the Command Bar of the Customer List and override the code for the Add button: 
  13. Paste the following code into the CustomerListAddAndEditNew_Execute method:

    this.Application.ShowCustomerDetail(null);

    This code passes null as the customer ID parameter to the screen which will cause the screen to create a new entity.
  14. Go back to the screen designer and override the code for the Edit button in the same way you did for the Add button.  Paste the following code into the CustomerListEditSelected_Execute method:

    this.Application.ShowCustomerDetail(this.Customers.SelectedItem.Id);

    This code passes the ID of the currently selected customer which will cause that customer to be loaded into the CustomerDetail screen.

With these changes, you can now edit the CustomerDetail to behave however you want and you will have a consistent experience when creating a new customer or editing an existing customer.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 23 Aug 2010 19:13

Today is the day where everyone can now download Beta 1 of Visual Studio LightSwitch.  Check it out!

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 23 Aug 2010 19:01

LightSwitch lets you configure your applications to use authentication.  This allows you to control who is able to access the application and lets your business logic know who the current user is.

Configuring the type of authentication to use

LightSwitch developers can choose what type of authentication to use for their application.  The options are no authentication (the default), Windows, or Forms.  For Windows authentication, the application user’s Windows credentials are used to authenticate their identity.  For Forms authentication, the application user must login with a user name/password combo to be authenticated.

 Access Control tab screenshot
Access Control tab (Beta 1)

Side note:

One interesting feature for a LightSwitch developer allows for the application to be debugged without needing to sign in.  So if the application is configured with Forms authentication, the developer can hit F5 to run the app and not have to worry about signing in.  Otherwise, the sign-in screen would be a major nuisance during iterative development.  Not until an application is deployed will the user be prompted to sign in.  If you have code which checks for the current user, it’ll still work when you are debugging even though you haven’t explicitly registered a user.  A transient test user is used as the currently running user.  Post-beta 1, LightSwitch will actually use your current Windows credential as the currently running user when using Windows authentication. 

Current user API

A LightSwitch developer always has access to determine who the current user is.  When writing code within a Table or a Screen, for example, you have access to the current user through the following code:

Microsoft.LightSwitch.Security.IUser currentUser = this.Application.User;

This provides access to the user’s username, full name, and other important bits of information like permissions and roles.

Managing your users

Users are managed within the running application.  Only users with the built-in SecurityAdministration permission have the ability to manage users.  By default, the administrator account that was specified when the application was published has the SecurityAdministration permission assigned to it.  Those users with this permission will see the Administration navigation group with a Users and Roles screen when they open a LightSwitch application.  (This is the default behavior for a new LightSwitch application.  The developer is free to rename or remove the Administration group, create a new navigation group for the administration screens, or even add custom screens to the Administration group.  This can be done through the Screen Navigation tab of the application properties of the LightSwitch project.)

Administration ScreensAdministration Screens (Beta 1)

You can manage your users in the Users screen:

Users ScreenUsers Screen (Beta 1)

Side note:

When using Windows authentication, the registered users are stored independently of Active Directory.  This means there is no need to administer the domain by adding certain users to a group in order to give them access to a LightSwitch application.  The users are directly managed through the LightSwitch application.  This was an intentional design decision since many LightSwitch apps are going to be departmental apps where the person administrating the app doesn’t have permission to make changes to the company’s Active Directory.

Authentication during application start-up

When a LightSwitch application is configured with Forms authentication, the user is automatically prompted for their user name and password:

Log-in prompt screenshot
Log-in prompt (Beta 1)

When using Windows authentication, the user is automatically authenticated through their Windows credentials when the application is opened so no prompt is shown.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch, Security"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 18 Aug 2010 19:35

The beta release of Visual Studio LightSwitch has just been made available via MSDN subscription!  You can find it at http://msdn.microsoft.com/subscriptions/downloads.  Just select Developer Tools –> Visual Studio 2010 and you’ll see it at the top of the list.  Download it and have fun.  Let us know what you think.

Author: "Matt Thalman"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 16 Aug 2010 20:40

Visual Studio LightSwitch is all about creating LOB applications.  And, of course, managing who can access the data in those applications is highly important.  LightSwitch aims to make the task of managing security simple for both the developer and the application administrator.

Here are the basic points about security within Visual Studio LightSwitch:

  • It has built-in support for Windows and Forms (user name/password) authentication.
  • It supports application-level users, roles, and permissions. Management of these entities are handled within the running application through built-in administration screens.
  • Developers are provided with access points to perform security checks.
  • It is based on, and an extension of, ASP.NET security.  In other words, it makes use of the membership, role, and profile provider APIs defined by ASP.NET. This allows for a familiar experience in configuration and customization.

I’ll address each of these bullet points in detail in subsequent blog posts.  Let me know your questions and concerns so that I can address them in those posts.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch, Security"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 09 Aug 2010 15:59

I’m back.  And this time for good.  I promise.

During the past couple of years, I’ve been working on a cool new developer tool product called Visual Studio LightSwitch.  If you haven’t heard of it, Jason Zander has a good blog post about it which you should read.  Basically, it’s a new rapid application development SKU in Visual Studio that lets you build LOB applications for the desktop or web.  And last week it was finally publicly announced with a beta due to drop on August 23.

This has been a fun product to work on and I’m excited for the world to see it.  Going forward in this blog, I will be writing about my experiences in using LightSwitch to build applications as well as some detailed information on the features areas for which I am responsible (such as authentication and authorization).  I plan to offer tips and tricks on how you can best use LightSwitch to create your applications.  And most of all, I’d love to respond to any of your questions on LightSwitch.

Author: "Matt Thalman" Tags: "Visual Studio LightSwitch"
Comments Send by mail Print  Save  Delicious 
Next page
» You can also retrieve older items : Read
» © All content and copyrights belong to their respective authors.«
» © FeedShow - Online RSS Feeds Reader