Shrinking a LightSwitchV3 project for file transfer

Introduction

A small LightSwitch solution can take quite some diskspace, ~150MB.

Since the LSv1 beta version, there’s a batch file made by Oscar Agreda for shrinking some redundant folders that Visual Studio creates when building in debug or release.

With the current version of LightSwitch, you have 2 options for cleaning your project: using an update of this batch, or by using the Clean Solution functionality of Visual Studio.

LSCleanV3.bat

Here’s an update of the script that works with the current version of LightSwitch, having a Desktop and/or a HTML Client:

 rd /q /s Bin\Debug
 rd /q /s Bin\Release
 rd /q /s _Pvt_Extensions

for /d %%p in (*Client) do (
 rd /q /s "%%p\Bin\Debug"
 rd /q /s "%%p\Bin\Release"
 rd /q /s "%%p\obj\Debug"
 rd /q /s "%%p\obj\Release"
 )

for /d %%p in (*Server) do (
 rd /q /s "%%p\Bin\Debug"
 rd /q /s "%%p\Bin\Release"
 rd /q /s "%%p\obj\Debug"
 rd /q /s "%%p\obj\Release"
 )

Remember to close your solution first, then run the script from your LS project folder.
With this script you can shrink the project folder to ~15MB, compressable to 3MB.

Clean Solution

With the first LightSwitch version, cleaning up the solution didn’t work for the LightSwitch project.
The current version has fixed this so you can also remove the redundant build files by cleaning your solution, do this once for each build configuration you used. This also cleans up the build files of additional projects, for instance your RIA Service class library project, which the batch file doesn’t.

After the clean, you can manually delete the _Pvt_Extensions folder.

Enjoy!
Michiel

Advertisements

Computed Fields in the HTML5 client

Introduction

The motivation of LS has always been to make typical LOB patterns easy to implement without limiting the more advanced functionalities.

With the introduction of the HTML Client however, some comforts when developing LS Silverlight applications have disappeared. Many of you feel like JavaScript is holding you back. JavaScript is a powerful language, but definitely requires some studying when you’re accustomed to a strongly typed class-based OOP language like C# or VB.NET.

So let’s start with learning how to implement computed fields in the HTML Client.

Computed Properties in the HTML Client

Currently, there are 2 ways to do this:
– By using a RIAService
– By using the contentItem databinding

Implementing computed properties by extending your entity with a RIA Service is well described in this post by Michael Washington. It is great when having a more complex computation or when you’ll also want to sort or query on the property. However, it also adds some complexity to your code and has a negative impact on maintainability.

Computed properties by using the contentItem databinding is a great option when you’re not afraid of some JavaScripting. So let’s found out a good pattern, in a Object-Oriented way!

Create a simple application with a entity Customer. A customer has a First Name and a Last Name and … a computed full name.
At the Server-side and the SL Client, you can use a shared function for this.


public partial class Customer
{
  partial void FullName_Compute(ref string result)
  {
    result = String.Format("{0} {1}",FirstName,LastName);
  }
}

At the HTML Client however, you can’t add a computed field by using the designer. So let’s do some JavaScripting! (add your own emotion ;))

Open up the Customer.js file and add the following function to the Customer’s prototype.

myapp.Customer.prototype.getFullName = function () {
  /// <summary>Computes the full name of the person.</summary>
  /// <returns type="String">The full name.</returns>
  if (this.FirstName && this.LastName) {
    return this.FirstName + " " + this.LastName;
  }
  return "";
};

By doing this, you’ve added a ‘public’ function to the Customer objects (instantiated after or before this line!). If you’re not familiar with JavaScript, MDN offers some nice documentation, including a introduction to Object-Oriented JavaScript. If you frown when you hear OOP and JavaScript in the same sentence, you’ve got some reading to do 🙂

Note that we’ve also added some Intellisense documentation. Every time we are using a Customer object, we can now see some documentation about our added computed fields if we reference this js file.

Now add a Browse screen and a Add/Edit screen for your Customers.
At the browse screen, use the postrender event of the Customer rowtemplate to replace the summary text shown:

/// <reference path="../GeneratedArtifacts/viewModel.js" />
/// <reference path="Customer.js" />
myapp.BrowseCustomers.RowTemplate_postRender = function (element, contentItem) {
  function updateCustomerRow() {
    /// <var type="myapp.Customer"></var>
    var customer = contentItem.value;
    $(element).text(customer.getFullName());
  }
  contentItem.dataBind("value.FirstName", updateCustomerRow);
  contentItem.dataBind("value.LastName", updateCustomerRow);
};

Note that the Intellisense for JavaScript doesn’t provide an accurate list of identifiers for the contentItem object.
Intellisense

However you can help Intellisense by declaring the variable as a Customer object. By doing this and referencing the added functions to the Customer prototype, you should now see your computed property function:
Intellisense2

This was easy, up to the Add/Edit screen. Drag the Customer data item to the first rows layout and change the added control to a summary control. Change the display name to Full Name and data bind analogously as with the RowTemplate in the Browse screen.
AddEditCustomer

Some improvements

This pattern is a basic building block and can easily be improved.

  • It would make sense to override the Customer toString function with a custom summary property. However, at first sight the entity’s summary property doesn’t make use of the toString function.
  • You can DRY the dependency data binding by implementing a function like this on the Customer prototype:
    myapp.Customer.prototype.bindToFullName = function (contentItem,callbackFn) {
      /// <summary>Bind to the full name</summary>
      /// <param name="contentItem" type="Element">The contentItem element.</param>
      /// <param name="callbackFn" type="function">The function to call back when the data binding is triggered.</param>
      contentItem.dataBind("value.FirstName", callbackFn);
      contentItem.dataBind("value.LastName", callbackFn);
    };
    

    This would be especially useful when you are dealing with a dependency chain!

Conclusion

We now have 2 good solutions for having a computed property. One does not supersede the other, evaluate case by case which solution you’ll use!