Saturday 3 November 2012

Running Python in Silverlight

The Problem

I recently needed to run a function within my Silverlight client where the Silverlight code had no knowledge of the implementation.  This logic would need to be configurable but would always maintain the same interface,

Rather than calling out to a web server every time I wanted to run this function, I wanted the function itself to retrieved from the server on start up of the Silverlight client.  How could I achieve this goal of meta programming?

One way is with Python.

The Scenario

My Silverlight client would like to know how to calculate the commission based on a startdate and enddate without hitting a web service for each commission calculation.

To get this commission my web server will reading data from a database table to create this logic table:

Less than 3 months = 1%

Between 3 months and less than 6 months = 2%

Between 6 months and 12 months = 3%

This logic and data would be highly configurable with the number of months, the number of conditional lines, the commission rate all subject to change.  More over the logic itself could change, perhaps certain customers might get a better commission rate.

The Solution

So I could expose the script from a web service, allowing my web server to dynamically compose the script from data retrieved from a database.

On start up my Silverlight client would call the web service to receive the script in JSON format. 

The Silverlight client can then parse the script and execute the function within C# at any point.  Simple.

image

using System;
using System.Windows;
using Microsoft.Scripting.Hosting;

namespace ScriptingInSilverlight
{
public partial class MainPage
{
public MainPage()
{
InitializeComponent();

// call web service to get Python script, for this demo we are hard coding the script here

Python.Text = "def calculateCommission(start, end):" + Environment.NewLine +
" if (end < start.AddMonths(3)):" + Environment.NewLine +
" return 1" + Environment.NewLine +
" elif (end >= start.AddMonths(3) and end < start.AddMonths(6)):" + Environment.NewLine +
" return 2" + Environment.NewLine +
" elif (end >= start.AddMonths(6) and end <= start.AddMonths(12)):" + Environment.NewLine +
" return 3";

}

private void PythonButton_Click(object sender, RoutedEventArgs e)
{
try
{
ScriptEngine engine = IronPython.Hosting.Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
engine.Execute(Python.Text, scope);

Func<DateTime, DateTime, int> function;
if (!scope.TryGetVariable("calculateCommission", out function))
{
PythonResult.Text = "No function calculateCommission defined";
return;
}

var result = function(new DateTime(2012, 11, 02), new DateTime(2012, 12, 31));

PythonResult.Text = "RESULT = " + result + " % commission";
}
catch (Exception ex)
{
PythonResult.Text = string.Format("Exception running script: {0}", ex.Message);
}
}
}
}

Source code:  https://github.com/stevenh77/ScriptingInSilverlight

DLR JScript was dumped by the Microsoft Dynamic Language Runtime team in favour of Ruby and Python, which have also since been laid rest as far I can tell:


http://msdn.microsoft.com/es-es/library/cc645049(v=vs.95).aspx

No comments:

Post a Comment