Nuget Package for setting up an internal RIA Service for your LightSwitch project.

Introduction

I like to automate as much as possible repetitive tasks mainly because I don’t like repetitive work but also because automation can reduce the number of errors and it just gives a nice feeling when one can get rid of something annoying.

Adding a RIA service to a LightSwitch project is such a repetitive task…

Therefore, I created a Nuget Package for setting up an internal RIA Service that can get attached via a .Net class library project to your LightSwitch solution.

Why an internal RIA service ?

Often, the pure entity driven approach of LightSwitch is not sufficient and you want to create Data Transfer Objects (DTO) which make up a kind of aggregation between different entities. A good example of such a DTO is an aggregation of a Customer, Order and City entity:

public class CustomerDTO
    {
        [Key]
        public int Id { get; set; }
        public string CustomerName { get; set; }
        public string City { get; set; }
        public decimal? TotalOrdersQuantity { get; set; }
    }

In many cases, “computed properties” can handle such aggregations as well, but there can be reasons (e.g. performance) why you do not want to use these.

Why is setting up an internal RIA service repetitive?

  • the RIA service class library needs a lot of assembly references (e.g. System.ComponentModel.DataAnnotations.dll)
  • the RIA service class library needs a linked file reference to ApplicationData.cs from the ServerGeneratedProject
  • it has practical advantages to refactor base functionality of each DomainService in a base class called LightSwitchDomainServiceBase, which inherits from DomainService. Basically, this base class takes care of the low level plumbing of the domain context and carries the Count() method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.DomainServices.Server;
using ApplicationData.Implementation;
using System.Data.EntityClient;

namespace RiaService
{
    public  class LightSwitchDomainServiceBase:DomainService
    {
        #region Database connection
        private ApplicationDataObjectContext m_context;
        public ApplicationDataObjectContext Context
        {
            get
            {
                if (this.m_context == null)
                {
                    string connString =
                        System.Web.Configuration.WebConfigurationManager
                        .ConnectionStrings["_IntrinsicData"].ConnectionString;
                    EntityConnectionStringBuilder builder = new EntityConnectionStringBuilder();
                    builder.Metadata =
                        "res://*/ApplicationData.csdl|res://*/ApplicationData.ssdl|res://*/ApplicationData.msl";
                    builder.Provider =
                        "System.Data.SqlClient";
                    builder.ProviderConnectionString = connString;
                    this.m_context = new ApplicationDataObjectContext(builder.ConnectionString);
                }
                return this.m_context;
            }
        }
        #endregion
        // Override the Count method in order for paging to work correctly
        protected override int Count<T>(IQueryable<T> query)
        {
            return query.Count();
        }
    }
}
  • A class library has by default a class called class1.cs.  You want to remove this, don’t you?
  • I included as well 2 classes which serve as a (minimal) example on how to create a custom domain service and a DTO. The DTO is enlisted already above. This is the example domain service:
namespace RiaService
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using RiaService.DTO;
    using System.ServiceModel.DomainServices.Server;

    public class CustomerDomainService : LightSwitchDomainServiceBase
    {

        [Query(IsDefault = true)]
        public IQueryable<CustomerDTO> GetCustomersDTO()
        {
            return from c in this.Context.Customers
                   select new CustomerDTO
                   {
                       Id = c.Id,
                       CustomerName = c.LastName,
                       City = c.City.CityName,
                       TotalOrdersQuantity = c.Orders.Sum(o => o.Quantity)
                   };
        }
    }
}
The NuGet package I created, is doing the above automatically for you.

How to use the RiaLightSwitch Nuget Package?

In case you don’t know what NuGet is, I suggest you go to nuget.org.

Step 1: Install NuGet (in case you don’t have it yet)

Go in visual studio to the extension manager (from the tools menu  - Extension Manager) and install NuGet.

 Step 2: In a LightSwitch solution add a plain .net 4 class library project.

The name of the class library doens’t matter (I realise now that I have only foreseen a scenario for c#).

You will see now in the project explorer your newly added class library. It has the class1.cs, but the NuGet package will remove this :)

Step 3: install the RiaLightSwitch package

Rightclick your newly added class library and select “Manage NuGet Packages”, this will open again the extension manager, but this time for installing the NuGet package.

This will trigger the package installation.

Alternatively you could do the same, via the  package manager console (go to Tools – Library Package Manager – Package Manager Console). Make sure your class library is in the default project dropdown and type “Install-Package RiaLightSwitch”

 

The package makes sures that there are folders for the DTO’s and the Services. Also the link to the ApplicationData.cs is present.

 

 

The internals

In case you interested in the internal of the NuGet Package, you could download it via the Nuget package explorer.

My RiaLightSwitch package is simple, but nonetheless, it contains a powershell script, where the most tricky part is the addition of the ApplicationData.cs link from the ServerGenerated project to the class Library.

Here is the code of the Install.ps1 powershell script:

param($installPath, $toolsPath, $package, $project)

Add-Type -Assembly EnvDTE100

#if your naming convention system means having class names like Class1 you have a problem now
ForEach ($item in $project.ProjectItems) 
{
	if($item.Name -eq "Class1.cs")
	{
		$item.Remove()
	}
} 

$applicationDataFileExists = $false
ForEach ($item in $project.ProjectItems) 
{
	if($item.Name -eq "ApplicationData.cs")
	{
		$applicationDataFileExists = $true
	}
} 

if($applicationDataFileExists -eq $false)
{
	$solution = get-interface $dte.solution ([EnvDTE100.Solution4])
	$solutionRoot = split-path $solution.filename
	$solutionFolderName = (Get-Item (Split-Path $solution.fileName -parent)).Name
	$project.ProjectItems.AddFromFile($solutionRoot + "\" + $solutionFolderName + "\ServerGenerated\GeneratedArtifacts\ApplicationData.cs");
}

My powershell skills are poor, so I will not feel offended if you have suggestions for improvement.

Conclusion

This was my first NuGet package. Although it works on my machine,  I hardly can’t imagine that there will be situations in which the package doesn’t work. Drop me a line, and I’ll look into it.