Design time sharing the LightSwitch database with a worker process (part 2/2)

Introduction

Let’s try to do things differently now.

Instead of adding a new .edmx file, we’ll share the ObjectContext from the LightSwitch app to the worker process in a way that resembles the way how a Ria Service is integrated with LightSwitch.

But… It’s different.

Why is this a different setup compared to the integration of a RIA Service into LightSwitch.

At first glance, the above setup looks quite similar to how a Ria Service can be integrated in LightSwitch. See: http://msdn.microsoft.com/en-us/library/vstudio/gg589479.aspx.

In the above article the connection to the LightSwitch entity framework meta data are retrieved as follows:

protected override NorthwindEntities2 CreateObjectContext()
{
     EntityConnectionStringBuilder Connection = new EntityConnectionStringBuilder();
     Connection.ProviderConnectionString = _connectionString;
     Connection.Provider = "System.Data.SqlClient";
     Connection.Metadata = "res://*/NorthwindModel.csdl|" +
                  "res://*/NorthwindModel.ssdl|" +
                  "res://*/NorthwindModel.msl";
     return new NorthwindEntities2(Connection.ToString());
}

Nonetheless, there are some fundamental differences, which make that the above approach won’t work.  In the above approach, the metadata information is taken from resources baked in a binary way into the LightSwitch Application.Server dll. But, we don’t want to have a reference to this dll in our console application. Even more, if we would make add a binary reference to this dll, it won’t work neither.

So, we need a different way. Note that the differences are very subtle but substantial.

Solution Setup

We add a new worker process (a console app)  which looks as follows (after applying the next steps):

solutionsharedcontext

 

Apart from the binary references, we need also 4 file references (add the references as a file link, that makes that they are always in sync with the source).

 

 

Also make sure that for the 3 entity framework files (.csdl, .msl and .ssdl) you specify copy always :

copyoutput

The source folder of the file references points to the generatedArtefacts folder of the LightSwitch server project. Simply include the ApplicationDataObjectContext file and the 3 entity framework meta data files (ApplicationData.sdl, msl and ssdl)

Note that there is NO binary reference to the  LightSwitch server project, but we need a few other binary references:

 

binaryrefs

 

Create a LightSwitchObjectContext class

The magic here is that we do not link the entity framework files as a “resource”, but simply as a file. Since we specified to copy these files to the output folder we can reference them as “./ApplicationData.csdl”:

 

using LightSwitchApplication.Implementation;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.EntityClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WorkerWithSharedObjectContext
{

    public class LightSwitchObjectContext
    {
        private ApplicationData m_context;
        public LightSwitchObjectContext()
        {
            if (this.m_context == null)
            {

                string executable = System.Reflection.Assembly.GetExecutingAssembly().Location;
                string path = (System.IO.Path.GetDirectoryName(executable));
                string dbRoot = Path.Combine(Directory.GetParent(path).Parent.Parent.FullName, @"LightSwitchApp\Bin\Data");

                AppDomain.CurrentDomain.SetData("DataDirectory", dbRoot);

                string connString = ConfigurationManager.ConnectionStrings["_IntrinsicData"].ConnectionString;

                EntityConnectionStringBuilder builder = new EntityConnectionStringBuilder();

                // here is the magic: don't load the EF artefacts from the assembly resource but from a file reference.
                builder.Metadata = string.Format("./ApplicationData.csdl|./ApplicationData.ssdl|./ApplicationData.msl");

                builder.Provider = "System.Data.SqlClient";
                builder.ProviderConnectionString = connString;
                this.m_context = new ApplicationData(builder.ConnectionString);
            }
        }
        public ApplicationData GetContext()
        {
            return this.m_context;
        }
    }
}

Note, we apply the same technique for being able to specify the connection string path withe “DataDirectory” variable (see previous post for more details).

This allows very easy consumption of the entity framework model inside the Console Application:

using LightSwitchApplication.Implementation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WorkerWithSharedObjectContext
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ApplicationData applicationData = new LightSwitchObjectContext().GetContext())
            {
                var result = applicationData.Customers.First().LastName;
                Console.WriteLine("here we go: " + result);
                Console.Read();
            }
        }
    }
}

Of course you need an app.config to store the database connection string. In the debug environment you will want to connect to the same localdb as the LightSwitch application is connecting to:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<connectionStrings>
<add name="_IntrinsicData" connectionString="Server=(localdb)\v11.0;AttachDbFileName=|DataDirectory|\APPLICATIONDATABASE.MDF;Integrated Security=True;Connect Timeout=30;MultipleActiveResultSets=True" />
</connectionStrings>
</configuration>

 

This looks simpler than the previous technique. Why not always using this?

The drawbacks of this approach is:

  • You can not split things up into a data and domain layer (the LightSwitch generated ApplicationDataObject context file contains both the dbContent material as well as the domain classes).
  • You can not use a different entity framework version as the one used in LightSwitch.

Conclusion

As you can see in the example, our console application will have always the latest version of the LightSwitch object model. If you make a change in the LightSwitch data structures, you’ll get a compilation error. And that’s what we like, … even in a world full of java script…