Leave my endpoints alone!

By default, LightSwitch apps expose the server tier by one public OData endpoint per data-source. Both the desktop and the HTML client make direct calls to these .svc urls to retrieve the data they need.

So here’s an interesting question I got this afternoon: this means that all data is publicly visible?

Well, yes and no. The endpoints are publicly visible, however when you access them, the LightSwitch (actually asp.Net) framework’s authentication and authorization will kick in to protect the data (authentication determines if you can access the endpoint, authorization determines if you can access that particular entity set and what records you can access).

However, there’s some cases where you want to protect your endpoints even more, for example when you’re forced to build an application without authentication, or if you want to prevent a user with a valid username&pw (or windows credentials) to access the data from outside your own apps.

In that case, you can add a custom IHttpModule. This would include registering the module in your web.config…

  <system.webServer>  
    <modules>
      <add name="CustomHeaderModule" type="StrongNamespace.HttpModules.CustomHeaderModule"/>
    </modules>

and adding whatever code you want to your server project…

using System;
using System.Web;

namespace StrongNamespace.HttpModules
{
    public class CustomHeaderModule : IHttpModule
    {
        public void Init(HttpApplication application)
        {
            application.PostReleaseRequestState += new EventHandler(application_PostReleaseRequestState);
        }

        public void Dispose()
        {
        }

        void application_PostReleaseRequestState(object sender, EventArgs e)
        {
            if (HttpContext.Current.Request.Url.ToString().ToLower().Contains(".svc") 
                && !HttpContext.Current.Request.Url.ToString().ToLower().Contains("authenticationservice.svc")))
            {
                var referrer = HttpContext.Current.Request.UrlReferrer;
                if (referrer == null)
                    throw new Exception("Not allowed to access this data"); 
                else if (referrer.Host != HttpContext.Current.Request.Url.Host)
                    throw new Exception("Not allowed to access this data"); 
            } 
        }
         
    }
}

The above sample will block any calls to the .svc endpoints (your OData endpoints that expose your data) if the call is not made from a site within the same domain.

This hasn’t been production tested yet (and honestly you’ll probably need to customize the business rules a bit) but at first sight seems not to interfere with the LS desktop (OOB or inB) or HTML client, but do blocking any other calls.

It’s not really ‘web-friendly’ either, in production code I’d suggest rewriting the response to a 403-forbidden instead. But then again who gives a fuck about http status codes… (*grabs popcorn*)

 

Keep rocking LS!
Jan

Preventing a screen from closing in the LightSwitch desktop client

Every day, one of our end-users opens a screen and prints out all open support tickets for that day. When the tickets are printed, we want to make sure those tickets are marked as ‘printed’ on the server, so we have a button on the screen that lets her do just that:

        //Screen has one 'state' boolean
        private bool isMarkedAsPrinted = false; 

        //Normal code behind a button to mark tickets as printed
        partial void MarkAsPrinted_Execute()
        {
            if (!isMarkedAsPrinted)
            {
                foreach (var ticket in this.Tickets)
                    ticket.IsPrinted = true;
                this.Save();
                this.isMarkedAsPrinted = true; //Don't forget to change the screen's state
            }
            else
                this.ShowMessageBox("The tickets are already marked as printed.");
        } 

Sometimes, she’ll forget to press that button, so when the screen closes we want to check if the tickets are printed.  The screen has a ‘Write Code’ button for the _Closing event, and it is passed a bool called ‘cancel’. If you set this bool to ‘true’, the screen closing event will be cancelled.

        //Excecuted when the screen is closed
        partial void PrintTicketScreen_Closing(ref bool cancel)
        {
            //Cancel all closing events unless we set the 'reallyClose' flag 
            cancel = !(isMarkedAsPrinted); 
        }

That works like a charm. Once she prints, the isMarkedAsPrinted boolean is set to true, and the screen can close. When she forgets to press the button, the screen will not close no matter how many times the ‘x’ is clicked.

From a UX perspective though, this is rather weird. The application will just feel like it doesn’t respond to her trying to close the screen. We could have the screen show a message box saying she needs to print first, or better yet: asking her if she wants to print:

        //Screen has one 'state' boolean
        private bool isMarkedAsPrinted = false; 

        //Normal code behind a button to mark tickets as printed
        partial void MarkAsPrinted_Execute()
        {
            if (!isMarkedAsPrinted)
            {
                foreach (var ticket in this.Tickets)
                    ticket.IsPrinted = true;
                this.Save();
                this.isMarkedAsPrinted = true; //Don't forget to change the screen's state
            }
            else
                this.ShowMessageBox("The tickets are already marked as printed.");
        } 
         
        //Excecuted when the screen is closed
        partial void PrintTicketScreen_Closing(ref bool cancel)
        {
            //Cancel all closing events unless we set the 'isMarkedAsPrinted' flag 
            cancel = !(isMarkedAsPrinted);

            if (cancel)
            {
                var answer = this.ShowMessageBox("Would you like to mark these tickets as printed before closing the screen?", "Mark tickets as printed?", MessageBoxOption.YesNoCancel);
            switch (answer)
            {
                case MessageBoxResult.Cancel:
                    //Simply let the screen stay open in current state
                    break;
                case MessageBoxResult.Yes:
                    //Execute mark as printed, then close screen automatically
                    this.MarkAsPrinted_Execute();
                    cancel = false;
                    break;
                case MessageBoxResult.No:
                    //User doesn't want to mark as printed, close screen
                    cancel = false;
                    break;
                default:
                    throw new Exception("Unexpected result.");
            }
            }
        }

Something weird will happen when you run through the code though… When closing the screen, if the tickets haven’t been marked as printed, the dialog will be displayed to remind the user to save. However, half a second later, the screen will close anyways.

Here’s the rub: your screen’s _Closing event is given about one or two seconds to finish executing. When it does not finish executing within that timeframe, the LightSwitch framework will close every open dialog on the screen (including your ‘would you like to mark the tickets as printed’ one), and close the screen anyway.

The workaround is to make sure the _Closing event code returns immediately, but cancels the closing, on first run. Before we return from that method though, we’ll kick off a background worker. This background worker will ask the screen’s logical dispatcher to show the ‘would you like to mark the tickets as printed’ dialog. This request will be queued by the screen’s logical dispatcher and executed whenever it has time (read: whenever it is done not closing your screen).

Once the tickets are marked as printed, or the user refuses to mark the tickets as printed (perhaps the screen was opened by accident in the first place, or the printer ran out of paper), we’ll flip a boolean and close the screen programmatically. The second time the screen’s _Closing event code is executed, it’ll pick up this boolean (or notice the tickets have been marked as paid) and let the screen close this time:

        //Screen has two 'state' booleans
        private bool isMarkedAsPrinted = false;
        private bool userDoesNotWantToMarkAsPrinted = false;

        //Normal code behind a button to mark tickets as printed
        partial void MarkAsPrinted_Execute()
        {
            if (!isMarkedAsPrinted)
            {
                foreach (var ticket in this.Tickets)
                    ticket.IsPrinted = true;
                this.Save();
                this.isMarkedAsPrinted = true; //Don't forget to change the screen's state
            }
            else
                this.ShowMessageBox("The tickets are already marked as printed.");
        } 
         
        //Excecuted when the screen is closed
        partial void PrintTicketsScreen_Closing(ref bool cancel)
        {
            //Cancel all closing events unless we set the 'isMarkedAsPrinted' flag OR 'userDoesNotWantToMarkAsPrinted'
            cancel = !(isMarkedAsPrinted || userDoesNotWantToMarkAsPrinted);

            if (cancel)
            {
                //If this method takes longer than a second, the LS framework will close all dialogs as 'cancelled'
                //Hence, we start a backgroundWorker so that we can return from this method straight away
                var sleepy = new BackgroundWorker();
                sleepy.DoWork += (s, e) =>
                {
                    //This code will execute on the thread of the background worker, so
                    //we must ask the screen's dispatcher to invoke the 'askPrintBeforeClosing' 
                    //instead of asking this on the background worker's thread
                    this.Details.Dispatcher.BeginInvoke(() => { askPrintBeforeClosing(); });
                };
                sleepy.RunWorkerAsync();
            }
        }

        //Helper method
        void askPrintBeforeClosing()
        {
            var answer = this.ShowMessageBox("Would you like to mark these tickets as printed before closing the screen?", "Mark tickets as printed?", MessageBoxOption.YesNoCancel);
            switch (answer)
            {
                case MessageBoxResult.Cancel:
                    //Simply let the screen stay open in current state
                    break;
                case MessageBoxResult.Yes:
                    //Execute mark as printed, then close screen automatically
                    this.MarkAsPrinted_Execute();
                    this.Close(false);
                    break;
                case MessageBoxResult.No:
                    //User doesn't want to mark as printed, close screen automatically
                    userDoesNotWantToMarkAsPrinted = true;
                    this.Close(false);
                    break;
                default:
                    throw new Exception("Unexpected result.");
            }
        }

Keep rocking LS!
Jan

 

 

 

 

 

Loading of collections in the desktop client on a ‘need to see’ basis.

I just spent my Saturday afternoon on a really fun puzzle: loading data on a ‘need to see’ basis. This code hasn’t been production tested at all (use at own risk), but is way too fun not to share.

Challenge

The LightSwitch desktop application can sometimes feel really sluggish, this is partly because collections on a screen ‘execute automatically by default’, this means that they are loaded automatically if they are used in the UI, even if that part of the UI is not visible (for example if the grid is on a tab that is not active at the moment). So here’s the challenge: can we speed up the application by loading data on a ‘need to see’ basis? Can we make our application intelligent enough so that data is loaded if and only if it needs to be visualized?

I have a screen that contains a couple of collections, let’s say that Foo has a one-to-many relationship with Bar and I made a list-detail screen with three tabs, one containing the Foo’s details, one containing the Foo.Bars as a Data Grid, and one containing the Foo.Bars as a List.Image 247Or at runtime:Image 248

When I go to the Foos List Detail, using Fiddler or another network sniffing tool, I can see that both the Foos, and the first Foo’s.Bars are automatically loaded.Image 251

(Well: obviously, because in the screen designer both the Foo and Bars collection have their ‘Auto Execute Query’ selected…)Image 243

Making your application smarter

Add a new class to your client project, named ‘LoadOnDemandExtensions’. Copy the source for that class from this gist.  It’s in C#, but here’s a good link for our VB friends.

(For those of you that actually clicked the VB link, I’m sorry. That was mean. To make it up, I posted the VB code at the bottom of that same gist ;-) )

Step 2: right-click on the client code in Solution Explorer, hit ‘View Application Code’ to open your client application code. In the Application_Initialize method, write:

C#
    public partial class Application
    {
        partial void Application_Initialize()
        {
            this.LoadVisualCollectionsOnDemand(); 
        } 
    }
VB
    Public Class Application

        Private Sub Application_Initialize() 
            Me.LoadVisualCollectionsOnDemand() 
        End Sub
    End Class

End of blog post.

No, really!  Press F5 and see how your application is behaving when it starts up now:Image 249

Even though the ‘Auto Execute Query’ is still on for Bars, the Lightswitch application didn’t load them because they aren’t visible at the moment. As soon as you hit the ‘Bars’ tab:

Image 250

 What is this sorcery?

The LoadVisualsOnDemand method will dig in the LightSwitch extensibility model to grab a hold of the NotificationService. It’ll ask that NotificationService to be notified whenever a screen is opened.

When a screen is opened it’ll loop over every collection on that screen and use some nifty hacking techniques (reflection is forbidden in SL in-browser sandboxed applications, but there’s a little loophole) to turn off ‘Auto Execute Query’ on the loader of each collection.

Also, it will search the screen for any ‘ContentItem’ (that is the right-hand side of your screen designer, which looks like a ‘visual tree’) that is displaying a collection (in reality this’ll be your List, Data Grid, or SuperDynamicGrid really). It will ask to be notified whenever such a control becomes visible/hidden. As soon as this happens, it’ll re-hack the VisualCollection to turn the ‘Auto Execute Query’ back on/off based on visibility.

This results in your collection becoming loaded, working (apparently paging, sorting and quicksearch do not work using other screen performance tips) and staying in sync (for example, you click on another Foo, this causes the Bars to be reloaded)

tl;dr; LightSwitch will now ignore your ‘Auto Execute Query’ attempts and turn that on/off depending on visibility.

Noteworthy caveat

Bugs incoming! This method will control the ‘Auto Execute Query’ property on all collections, every screen. However, some of your code might already depend on the implicit assumption that a screen collection is loaded. Screen your screen code files, and if you spot a spot where you access a collection in code, make sure it’s loaded using this other nifty extension method.

C#
        partial void Method_Execute()
        {
            this.Bars.LoadIfNeeded();
            var count = this.Bars.Count; //for example
        }
VB
        Private Sub Method_Execute()
            Me.Bars.LoadIfNeeded()
            Dim count = Me.Bars.Count 'for example
        End Sub

But what if…

What if I don’t want this behavior on every screen?

Instead of turning this on on an application level, you can activate it on a screen-by-screen basis.

On those screens where you need it, turn off the ‘Auto Execute Query’ manually on each collection. Then, write this in the screens _Activated code:

C#
        partial void FoosListDetail_Activated()
        { 
            this.LoadCollectionsOnDemand();
        }
VB
        Private Sub FoosListDetail_Activated()
            Me.LoadCollectionsOnDemand()
        End Sub

What if I don’t want this behavior on every collection?

Instead of turning this on on an application or on a screen level, you can activate it on a collection-by-collection basis.

On those screens where you need it, turn off the ‘Auto Execute Query’ manually on those collections. Then, write this in the screens _Activated code (repeat for every collection):

C#
        partial void FoosListDetail_Activated()
        {
            this.Bars.LoadOnDemand();
        }
VB
        Private Sub FoosListDetail_Activated()
            Me.Bars.LoadOnDemand()
        End Sub

 

Keep rocking LS!

(But only the visible parts)

Jan

 

 

 

Coding tips #1: tell, don’t ask

As part of a new assignment, I have the privilege of working with a new team. Hey teamies! One of the things the team and I really want, is to make sure our code is clean and manageable. Hence, I’ll be putting up a coding tip once in a while on how you can improve your code for readability and maintainability.

Tell, don’t ask, is a reminder that you should endeavor to tell objects what you want them to do; do not ask them questions about their state, make a decision, and then tell them what to do (source).

In the LightSwitch world, entities are our models. All too often we are tempted to write code that asks the models about their state, then we take decisions about that state. For example:

if(currentCustomer.Orders.Any(c => c.ClosingCode.Code == "1209" || c.ClosingCode == "1304")
{
  //Preferred customer, add discount
  //More code here...
}

This works beautifully. It’s fast to write, any other developer can clearly read what’s going on, and it executes in 0ms flat (give or take a few ticks).

There’s a couple of issues with this type of coding though… First of all, how about readability? Can any developer clearly read what’s going on? Well, read: yes. Understand: no. If he/she does not know what these closing codes mean, he/she’s shit out of luck.  Secondly, there’s a maintenance issue. What if a closing code changes? What if a third closing code is added that makes a customer preferred, or one is removed? What if we want to support multiple tenants, and for one tenant closing code “1209” makes the customer preferred, but for another one it doesn’t?

In all of these likely cases, we’d have to loop over our entire code base and find all the spots where we ‘ask’ the object about its state, and then take actions accordingly, and update that code…

We can get a few quick wins in maintainability and readability by adding a new field to the ‘ClosingCode’ entity:

if(currentCustomer.Orders.Any(c => c.MakesCustomerPreferred)
{
  //Preferred customer, add discount
  //More code here...
}

It seems like just a small change, but adding this field to the ClosingCodes really improves readability (as a new developer, I don’t have to know about the actual codes), we can add/edit/delete closing codes that make a customer preferred, and we can support different closing codes for multiple tenants.

Almost there though: our code still has the hard-coded idea that a customer can only be preferred based on closing codes. What if one day we also want to make a customer preferred based on other parameters, like ‘simply being a nice person’?  This additional refactoring requires you to take a decision though: refactoring takes time, and time costs money. Are these scenarios likely to happen, or are they more of a ‘one day it’d be nice to have this’ (YAGNI – you ain’t gonna need it).

If there is a very real chance that these scenarios might happen, you can further reduce the complexity of the code by moving the ‘IsCustomerPreferred’ state into the Customer object, instead of keeping it hidden inside the OrderClosingCode table:

if(currentCustomer.IsPreferred)
{
  //Preferred customer, add discount
  //More code here...
}

Obviously, you’ll need additional code, for example when an order is closed, to tell the customer it is preferred or take that status away.

 

Keep rocking LS!

 

Jan

app-stitch extensibility: creating a custom app-stitch action

In case this is the first time you hear about app-stitch, you owe it to yourself (or to me ;-)) to have a look at our newest project. App-stitch is a visual rules engine, currently for VS LightSwitch projects only, that provides a visual interface to your server project, where  you and/or your end users can create custom business rules at run-time.

We’re currently still developing app-stitch horizontally: adding more capabilities to it, so that we can reach a stable API. Once our API is stable, we and hopefully other people too can build out additional channels. Each channel gives your app-stitch instance additional connections to custom or 3rd party services: twilio, paypal, …

Some people, myself included, simply cannot wait for a public, documented API, and want to start building out custom channels right now. We can do nothing but applaud this enthusiasm, so I decided to write this first introduction into our extensibility model.  This post assumes you have a LightSwitch application with a pretty up-to-date version of app-stitch installed (you can install app-stitch on any LightSwitch server project, you don’t need a license until 30 days after you’ve published an app). This LightSwitch application has a concepts of ‘Tasks’, and the goal of this blog post is to allow the end users to schedule a task as part of an app-stitch rule.

Creating the channel

In LightSwitch, there’s two different worlds: your entities and the definition of your entities (the lsml metadata files). App-stitch is very similar, to get things up and running you’ll need to provide app-stitch with two types of data: the actual triggers&actions, and classes that describe your channel and it’s triggers and actions to app-stitch (the metadata).

Let’s start with the metadata: describing your ‘task’ channel and ‘create a task’ action to app-stitch.  Right-click on your server project and add a new class called “TaskChannel.cs”. I’m going to do this post in C# but the code should be very easy to port to VB.

Describing your channel to app-stitch means you have to create a class which inherits AppStitch.Channel. The constructor of AppStitch.Channel takes 5 arguments:

- a name: this is the unique identifier of your channel. It should be a single word with no special characters (“TaskChannel”)

- a display name: this is the actual name that is shown to end users when your channel is in the UI (“Tasks”)

- a description: this is shown next to the channel so that users that are not familiar with your channel have access to a quick.. .well… description ;-)

- a list of Trigger definitions: empty at the moment (triggers are a bit trickier than actions so I’ll dedicate a separate post to it)

- a list of Action definitions: the available actions on this channel, currently containing one new ‘CreateATaskAction’

    public class TaskChannel : AppStitch.Channel
    {
        public const string TaskChannelName = "TaskChannel";
        public const string TaskChannelDisplayName = "Tasks";
        public const string TaskChannelDescription = "This channel allows you to schedule tasks";
        public TaskChannel()
            : base(
                TaskChannel.TaskChannelName,
                TaskChannel.TaskChannelDisplayName,
                TaskChannel.TaskChannelDescription,
                new AppStitch.TriggerDefinition[] { },
                new AppStitch.ActionDefinition[] { new CreateATaskAction() }
                )
        {

        }
    }

That won’t compile though, because there is no ‘CreateATaskAction’ class yet. Below your channel, add the ‘CreateATaskAction’ class. This class should inherit the AppStitch.ActionDefinition class and pass 6 constructor arguments:

- a name: this is the unique id of your action

- display name: this is the actual name that is used when your task is shown in the UI

- a description: this is shown next to the action so that users that are not familiar with your action have access to a quick.. .well… description ;-)

- one list of PropertyDefinitions that define the properties of your action. Properties are ‘values’ that the user has to fill in when he creates a rule for that uses this action. Each PropertyDefinition needs the name of the action it belongs to, the holy grail of ‘Name, DisplayName and Description’, and a list of possible string values (which will be displayed in a combobox), OR an ‘AppStitch.PropertyType’ which will determine how to display this property in the UI (password box, integer, string, HTML, …)  In addition, properties can be mandatory or optional too. I’ve added two properties in this code sample: ‘TaskPriority’ (a mandatory property which can be ‘Low’, ‘Normal’ or ‘High”) and ‘CCAddress’ (optional property which can be any string).

- one list of PropertyDefinitions that define the variables of your action. In app-stitch lingo, ‘properties’ need to be set when using the app-stitch UI to build a rule that contains this action, and ‘variables’ are simply values that exist on your action without needing to be configured. We’ll handle these in a next blog post.

- a priority. There’s three types of priorities: Validation, Instant and Low. You’ll likely only ever need ‘Instant’ or ‘Low’, and only need to remember that ‘Instant’ actions are executed whenever the rule fires, ‘Low’ actions will be scheduled to execute on a background worker thread, whenever your rule fires. The latter is useful if your action takes a while to complete (print a report, send an email, …)

    public class CreateATaskAction : AppStitch.ActionDefinition
    {
        public const string CreateATaskActionName = "CreateATaskAction";
        public const string CreateATaskActionDisplayName = "Create a task";
        public const string CreateATaskActionDescription = "This allows you to create a task";

        public const string PriorityPropertyName = "TaskPriority";
        public const string PriorityPropertyDisplayName = "The priority";
        public const string PriorityPropertyDescription = "The priority of this task: low, normal or high";

        public const string CCPropertyName = "CC";
        public const string CCPropertyDisplayName = "A CC email address";
        public const string CCPropertyDescription = "An email address that will receive a copy of this task";
        public CreateATaskAction()
            : base(
                TaskChannel.TaskChannelName,
                CreateATaskAction.CreateATaskActionName,
                CreateATaskAction.CreateATaskActionDisplayName,
                CreateATaskAction.CreateATaskActionDescription,
                new AppStitch.PropertyDefinition[] {
                new AppStitch.PropertyDefinition(
                    CreateATaskAction.CreateATaskActionName, 
                    CreateATaskAction.PriorityPropertyName, 
                    CreateATaskAction.PriorityPropertyDisplayName,
                    CreateATaskAction.PriorityPropertyDescription, 
                    new[]{"Low", "Normal", "High"}, 
                    isMandatory: true),
                    new AppStitch.PropertyDefinition(
                    CreateATaskAction.CreateATaskActionName, 
                    CreateATaskAction.CCPropertyName, 
                    CreateATaskAction.CCPropertyDisplayName,
                    CreateATaskAction.CCPropertyDescription, 
                    AppStitch.PropertyType.String,
                    isMandatory: false),
            },
                new AppStitch.PropertyDefinition[] { },
                AppStitch.ElementPriority.Instant
                )
        {

        }

        public override void ProcessEvent(AppStitch.IPropertyResolver propertyResolver)
        {
            //Create the task...             
        }
    }

Before we go into the ‘ProcessEvent’ method, we need one more step to finish the channel creation: the IChannelProvider.  This is a very simple class that takes your channel definition (and the action linked to it), and provides it to app-stitch on demand.

    public class TaskChannelProvider : AppStitch.IChannelProvider
    {
        private TaskChannel actualChannel = new TaskChannel();
        public IEnumerable GetChannels()
        {
            return new[] { actualChannel };
        }
    }

Your channel and it’s action are now fully exposed to app-stitch, and you and or your end users can now build rules against them. Create a new rule that fires on any trigger (your channel won’t be listed yet because it has no triggers), and once you get to add an action in your rule, you’ll see your channel appear:Image 233 Besides the channel’s display name and description, there’ll be a logo associated with your channel. Because you haven’t added a logo yet, it’ll just show the default app-stitch @-logo. If you drop a png named “TaskChannel.png” in your server project > appstitch > content > images, it’ll use that instead.

Clicking on the channel will reveal only one action.

Image 234

When you select your action, both your mandatory (priority) and your optional (CC address) property will be presented so that the user can configure your ‘Create a task’ action.

Image 235

Executing the action

Your channel is ready and can be used in a rule, but when that rule fires, nothing will happen yet. This is because your action has a method ‘ProcessEvent’, which is the method that will be called when your rule fires on a particular event, but it has no implementation yet.

        public override void ProcessEvent(AppStitch.IPropertyResolver propertyResolver)
        {
            //Create the task... 
        }

First thing to note is that the method is passed an AppStitch.IPropertyResolver.  You can ask this propertyResolver to resolve the values of the ‘Priority’ and ‘CCAddress’ property.  Because app-stitch allows you to use variables when designing your rules, this propertyResolver makes sure when the CCAddress property is set to ‘{{Customer:Email}}’, your action gets access to the actual meaningful, resolved value (‘bob@marley.com’, for example).

        public override void ProcessEvent(AppStitch.IPropertyResolver propertyResolver)
        { 
                var taskPriorityValue = propertyResolver.ParseStringProperty(CreateATaskAction.CreateATaskActionName, CreateATaskAction.PriorityPropertyName); 

            //Optional: send a CC
            if (propertyResolver.HasProperty(CreateATaskAction.CreateATaskActionName, CreateATaskAction.CCPropertyName))
            {
                var ccEmailAddress= propertyResolver.ParseStringProperty(CreateATaskAction.CreateATaskActionName, CreateATaskAction.CCPropertyName);
            } 
        }

Second thing of interest when implementing your action code, is how you can work with the ApplicationDataContext.  Your action could be firing as part of a rule that works within LightSwitch, in which case there’ll be an active ApplicationDataContext, but it could also fire as part of a rule that triggers outside of your LightSwitch application (‘new Twilio message’, ‘Timed event’, …).

This code sample shows you how to nail both cases in one:

            //Create the task
            ServerApplicationContext ctx;
            using (ItemUserAndContextProvider.GetCurrentOrNewApplicationContext(out ctx)) {
                
                var hasChanges = ctx.DataWorkspace.ApplicationData.Details.HasChanges; 
                //Create a task here:
                //var task = ctx.DataWorkSpace.ApplicationData.Tasks.AddNew();
                //task.Priority = taskPriorityValue;


                if (!hasChanges)
                    ctx.DataWorkspace.ApplicationData.SaveChanges();

            }  

Small recap: here’s how you could implement an action:

        public override void ProcessEvent(AppStitch.IPropertyResolver propertyResolver)
        {
            //Create the task
            ServerApplicationContext ctx;
            using (ItemUserAndContextProvider.GetCurrentOrNewApplicationContext(out ctx)) {
                var taskPriorityValue = propertyResolver.ParseStringProperty(CreateATaskAction.CreateATaskActionName, CreateATaskAction.PriorityPropertyName);
             
                var hasChanges = ctx.DataWorkspace.ApplicationData.Details.HasChanges; 
                //Create a task here:
                var task = ctx.DataWorkSpace.ApplicationData.Tasks.AddNew();
                task.Priority = taskPriorityValue;


                if (!hasChanges)
                    ctx.DataWorkspace.ApplicationData.SaveChanges();

            }  

            //Optional: send a CC
            if (propertyResolver.HasProperty(CreateATaskAction.CreateATaskActionName, CreateATaskAction.CCPropertyName))
            {
                var ccEmailAddress= propertyResolver.ParseStringProperty(CreateATaskAction.CreateATaskActionName, CreateATaskAction.CCPropertyName);
            //Send the CC
            } 
        }

Conclusion

That was crazy.

No seriously, extending app-stitch will not be an easy task, but if you follow this guide and copy-paste along, I’m sure you’ll reach that ‘aha’-moment and will be creating custom channels in no time.

If you do happen to create a custom channel that isn’t specific to a single application, please do drop us a message. We’re some iterations away from starting on our channels-store, at which point you could gift or sell your channel to the app-stitch end users!

Keep rocking LS!

Jan

PS: if you run into problems when creating your custom channels/triggers/actions, mail us your issue and we’ll do whatever needs to be done ;-)

PPS: Yes, this API is bound to change at some point as we add new features. We’ll provide you with a smooth upgrade path.

LightSwitch UX: Sharepoint-like tiles

Great, I’m pretending I know anything about UX nowadays… 

The LightSwitch HTML client, by default,  comes with a nice blue-on-white background style. This style matches the O365 one perfectly, providing the users with a smooth and consistent experience when you’re building Cloud Business Apps.

One of the nice controls in O365 are those tiles-with-an-overlay:

Image 215

For those of you that haven’t seen these, basically they are a clickable tile (‘a button’), with a title that expands to show the description when you mouse-over them (like the third tile).

Must… Have…

Step one: create a ‘home’ screen. Add a couple of buttons to the screen (NOT: to the command bar of the screen) and give them a nice display name and a description.

Image 216

Make sure their ‘height’ is set to ‘Fit to Content’, the JQuery plugin takes care of sizing already.

Next up: grab the CSS from this gist, and add it to the user-customisation.css file found in your HTML client project.  Also, grab the JQuery plugin and add it to your project (add a new JS file, then link it from default.html).

Finally, Edit the PostRender on each button and activate the plugin:

myapp.menuHome.buttonResources_postRender = function (element, contentItem) {
    $(element).spOverlay(contentItem, 'Content/Images/TouchIcons/ResourcesLarge.png'); 
};

myapp.menuHome.buttonDesigns_postRender = function (element, contentItem) {
    $(element).spOverlay(contentItem, 'Content/Images/TouchIcons/DesignsLarge.png');
};

myapp.menuHome.buttonProjects_postRender = function (element, contentItem) {
    $(element).spOverlay(contentItem, 'Content/Images/TouchIcons/ProjectsLarge.png'); 
};

Or if you want to customize the size (default 225 px):

  $(element).spOverlay(contentItem, 'Content/Images/TouchIcons/ResourcesLarge.png', {height:150, width:150});

F5 that shizzle!

Image 213

(Need to replace the blue on white icons with white on blue ones, I know ;-))

Keep rocking LS!!
Jan

Addendum: Multi-tenant LightSwitch applications: favor convention over configuration.

Wut wut, did I not already cover the generic multi-tenant filter in my previous blog post? Well how observant of you, dear reader, I most certainly did. However, in this post I’d like to elaborate a bit about a hidden ‘convention’ in PowerProductivityStudio.Server, the nuget package that you install on your LightSwitch server project to weave generic code entry points into your application.

See, when we (me and my alter ego) initially built PPS, we already had the idea in mind to use these generic code entry points to facilitate multi tenancy. Multi-tenancy is where a single deployed instance of a (LightSwitch) app is used by multiple groups of users (each group is a tenant), who share the hosting costs of the server and the database. This means that their data is in the same tables, and must thus generally be filtered so that tenants cannot view, let alone alter, data that belongs to another tenant.

Additionally, we figured that some default data would sometimes be common between different tenants as well. This data can be seen by any of the tenants, but changed only by the administrator.

In a nutshell, we needed an easy way for any LightSwitch project to:

  • filter data based on the TenantId of that data
  • show data that belongs to tenant “0” (default, shared data)
  • prohibit any changes/creations to data that belongs to tenant “0” (default, shared data)
  • make sure when a user creates a record, that data is correctly labeled with the correct TenantId
  • make sure when a user tries to update or delete data that belongs to a different tenant, this is blocked by the application.

Now, if these requirements sound like something you require (pardon my English vocabulary on Mondays…), you’ll be glad to find out that PPS has a hidden convention.

Here’s how that works:

Step one: add an integer “TenantId” column to any data that needs filtering, for example:

Image 183

Note: I suggest turning off ‘Show by default’ and setting the TenantId property as nullable. This way, the client will not ever have to bother with the property.

Now, just as a test, go to the Project entity where you added the TenantId property, and hit the “Write Code” > “Projects_Filter” button.

Image 190

A method stub will be generated that has one argument, and a code comment with a suggestion on how you can implement a filter here.

Put a breakpoint in the generated method stub and run the application. By default, you’ll notice that the ‘Filter’ argument is null…

Image 191

Instead of manually coding a lambda expression that filters records though, we’re going to use a convention in PowerProductivityStudio…

Wait, in whut whut?

Step two: install the PowerProductivityStudio.Server nuget package on your LightSwitch server project. PPS is a nuget package that contains a code weaving task. This task will add generic ‘code entry’ point to your application, so you can write code when ‘any entity is created/updated/deleted/queried’, …  This way you can create a generic filter at runtime, like in my previous post. However instead of writing a generic filter, we’ll take it one step further than my previous post again.  To install PowerProductivityStudio.Server, right-click on your server project and select ‘Manage nuget packages’. Search for ‘PowerProducitivityStudio.Server’ and install it.

Step three: tell PPS about your current tenant. To do this, add any class to your LightSwitch server application and implement the PowerProducitivityStudio.Extensibility.IMultiTenantService interface, for example:

using System.Web;
using Microsoft.LightSwitch;

namespace LightSwitchApplication
{
    public class MyMultiTenantService : PowerProductivityStudio.Extensibility.IMultiTenantService
    {
        public int GetCurrentTenantId()
        {
            return 1;
        } 
    }
}

Step four: launch your application!

If you still have your breakpoint in the ‘Projects_Filter’ method, you’ll notice that the query no longer is ‘null’, but actually has a valid ‘Multi-Tenant-Filter’ now…

Image 192

Succes? Let’s see…Image 184

All done… We just found an easy way for any LightSwitch project to:

  • filter data based on the TenantId of that data
  • show data that belongs to tenant “0” (default, shared data)
  • prohibit any changes/creations to data that belongs to tenant “0” (default, shared data)
  • make sure when a user creates a record, that data is correctly labeled with the correct TenantId
  • make sure when a user tries to update or delete data that belongs to a different tenant, this is blocked by the application.

Too easy? To short of a blog post?

Well, I could elaborate a bit more about my progress in learning Spanish (I can conjugate 12 verbs now, and know 27 different ways to order a beer), or I could help you a bit with that multi-tenant filter implementation.

First suggestion I would have for your multi-tenant filter (I know you’re not interested in my Spanish progress) would be to not hardcode it to “return 1;”.  You could set up a table that stores all tenants and their corresponding HostURL (for SharePoint provider hosted apps, like in the last post), or add a related table that stores which login (/user) belongs to which tenant.

Then, when PPS asks you for the tenant, just look that up using the ServerApplicationContext:

using System.Web;
using Microsoft.LightSwitch;

namespace LightSwitchApplication
{
    public class MyMultiTenantService : PowerProductivityStudio.Extensibility.IMultiTenantService
    { 
        public int GetCurrentTenantId()
        {
            var user = ServerApplicationContext.Current.DataWorkspace.ApplicationData.Users.Where(u => u.Login == ServerApplicationContext.Current.Application.User.Name).Single();
            return user.Tenant.Id;
        } 
    }
}

Sweet, but this will bog your system down quite a bit, since any data that is being retrieved/edited, will result in at least one extra call. Below is a revised version that will cache the current tenant id for a particular user in the HttpContext.Current.Cache. In addition, it also takes scenarios in mind where there might not be an existing ServerApplicationContext (if you use Web API for your fancy word document generation, for example), and shaves some milliseconds of the query by retrieving the User and it’s Tenant at the same time.

using System.Web;
using Microsoft.LightSwitch;

namespace LightSwitchApplication
{
    public class MyMultiTenantService : PowerProductivityStudio.Extensibility.IMultiTenantService
    { 
        public int GetCurrentTenantId()
        {
            int tenantId;
            if (HttpContext.Current == null //can happen if you have custom Web API calls
                || HttpContext.Current.Session["CurrentTenantId"] == null)
            {
                if (ServerApplicationContext.Current != null)
                {
                    var user = ServerApplicationContext.Current.DataWorkspace.ApplicationData.Users.Include("Tenant").Where(u => u.Login == ServerApplicationContext.Current.Application.User.Name).Single(); 
                    tenantId = user.Tenant.Id; 
                }
                else //can happen if you have custom Web API calls
                {
                    using (var context = ServerApplicationContext.CreateContext())
                    {
                        var user = ServerApplicationContext.Current.DataWorkspace.ApplicationData.Users.Include("Tenant").Where(u => u.Login == ServerApplicationContext.Current.Application.User.Name).Single();
                        tenantId = user.Tenant.Id;
                    }
                }
                HttpContext.Current.Session["CurrentTenantId"] = tenantId;
            }
            else
            {
                tenantId = (int)HttpContext.Current.Session["CurrentTenantId"];
            }
            return tenantId;
        }
    }
}

Badam tsss!

Just one more thing: PPS weaves the multi tenant filter just before the call is made to your “Projects_Filter” or “WhateverEntity_Filter” method.  There’s good news and bad news to that timing: if the multi-tenant filter that PPS creates does not fit your needs, you can easily overwrite it with whatever custom code you want, and re-assign the filter parameter. The bad news: if you already have a filter implemented (let’s say you only want projects with an ‘a’ in the name to appear), you’ll need to merge your custom filter and the existing filter together:

Image 194

 

Now, if you’ll actually try this, you’ll get a compilation exception, because combining two expressions is not supported unless you add this little helper class somewhere in your server project  ;-)

https://gist.github.com/janvanderhaegen/1620fee98ea8578862aa

Badam tsss again ;-)

Sample project has been uploaded to my OneDrive, and as always…

Keep rocking LS!