How to reference security entities in LightSwitch

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.