Python Programming, news on the Voidspace Python Projects and all things techie.

Embedding IronPython in a Silverlight Application

emoticon:pill Last week I posted an example of embedding IronPython in a Silverlight application. I tested this by compiling a Silverlight assembly and then executing the code from IronPython. Needless to say, this worked fine. Smile

Unfortunately it doesn't work when tried on its own. It throws a "The method or operation is not implemented" error when attempting to access PythonEngine.CurrentEngine.

Jimmy Schementi has come back and explained why this happens, and provided a fix:

When hosting IronPython in a normal C# app, the Hosting API makes some assumptions for that scenario and makes the hosting work "out of the box". Those assumptions are not all true in Silverlight, so a custom Platform Adaptation Layer (PAL) must be used.

Before you create the Python Engine:

ScriptEnvironmentSetup setup = new ScriptEnvironmentSetup(true);
setup.PALType = typeof(SilverlightPAL);
ScriptEnvironment.Create(setup);

This will override the default Silverlight PAL.

The solution is a bit verbose, but just needs some extra code where you embed IronPython. Eventually (hopefully) this will be moved into the DLR.

The C# code is below. You can also download the EmbeddedWithCodeBehind Project which is an example of (successfully) embedding IronPython in a C# Silverlight application...

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using IronPython.Hosting;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
using System.Reflection;
using System.Collections.Generic;

namespace EmbeddedWithCodeBehind
{
    public partial class Page : Canvas
    {
        public void Page_Loaded(object o, EventArgs e)
        {

            // Required to initialize variables
            InitializeComponent();

            try
            {
                ScriptEnvironmentSetup setup = new ScriptEnvironmentSetup(true);
                setup.PALType = typeof(SilverlightPAL);
                ScriptEnvironment.Create(setup);

                PythonEngine pe = PythonEngine.CurrentEngine;
                string code = "lambda x: x.upper()";
                Function<string, string> func = pe.EvaluateAs<Function<string, string>>(code);

                string x = "i'm talking loudly";
                string result = func(x);
                textBlock.Text = result;
            }
            catch (Exception ex)
            {
                textBlock.Text = ex.Message;
            }

        }
    }

    // Definition of Silverlight Platform Adoption Layer:
    public class SilverlightPAL : PlatformAdaptationLayer
    {
        public override Assembly LoadAssembly(string name)
        {
            return Assembly.Load(LookupFullName(name));
        }

        private Dictionary<string, string> _assemblyFullNames = new Dictionary<string, string>();

        public SilverlightPAL()
        {
            LoadSilverlightAssemblyNameMapping();
        }

        // TODO: This will not be necesary as it will eventually move down into the host
        private void LoadSilverlightAssemblyNameMapping()
        {
            AssemblyName clrAssembly = new AssemblyName(typeof(object).Assembly.FullName);
            foreach (string asm in new string[] { "mscorlib", "System", "System.Core", "System.Xml.Core" })
            {
                clrAssembly.Name = asm;
                _assemblyFullNames.Add(asm.ToLower(), clrAssembly.FullName);
            }

            _assemblyFullNames.Add("system.silverlight",
                 "System.SilverLight, Version=1.0.0.0, PublicKeyToken=b03f5f7f11d50a3a");
            _assemblyFullNames.Add("agclr",
                 "agclr, Version=0.0.0.0, PublicKeyToken=b03f5f7f11d50a3a");
            _assemblyFullNames.Add("microsoft.visualbasic",
                 "Microsoft.VisualBasic, Version=8.1.0.0, PublicKeyToken=b03f5f7f11d50a3a");

            AssemblyName dlrAssembly = new AssemblyName(typeof(PlatformAdaptationLayer).Assembly.FullName);
            foreach (string asm in new string[] {
                "Microsoft.Scripting",
                "Microsoft.Scripting.Silverlight",
                "IronPython",
                "IronPython.Modules",
                "Microsoft.JScript.Compiler",
                "Microsoft.JScript.Runtime",
                "Microsoft.VisualBasic.Compiler",
                "Microsoft.VisualBasic.Scripting",
                "Ruby"})
            {
                dlrAssembly.Name = asm;
                _assemblyFullNames.Add(asm.ToLower(), dlrAssembly.FullName);
            }
        }

        protected string LookupFullName(string name)
        {
            AssemblyName asm = new AssemblyName(name);
            if (asm.Version != null || asm.GetPublicKeyToken() != null || asm.GetPublicKey() != null)
            {
                return name;
            }
            return _assemblyFullNames.ContainsKey(name.ToLower()) ? _assemblyFullNames[name.ToLower()] : name;
        }

    }

}

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-09-04 23:27:26 | |

Categories: , ,


Blog Action Day

emoticon:dollars On 15th October, the distributed blogospheres that we all love (and loathe) so much will be alive with a mass action called:

  • Blog Action Day

    On October 15th, bloggers around the web will unite to put a single important issue on everyone's mind - the environment. Every blogger will post about the environment in their own way and relating to their own topic. Our aim is to get everyone talking towards a better future.

    Blog Action Day is about MASS participation. That means we need you!

I'll be taking part. If you blog and care about the environment, then get on board.

Like this post? Digg it or Del.icio.us it.

Posted by Fuzzyman on 2007-09-01 00:51:40 | |

Categories: ,


Hosted by Webfaction

Counter...