Uncategorized

IronPython console in your Web application

It isn’t common that small things can bring lots of joy into your software. For sure the subject of this post is one of them.

While testing and supporting large applications you are sometimes forced to do actions like checking some specific logic or preparing the data. What’s more, if you deal with an environment deployed by the Continuous Integration process, or simply the build process on your local machine lasts too long, you need to do some operations by hand (I mean by SQL etc.). Thus you see, that the most comfortable way of communicating with your software is the code and provided API. Unfortunatelly you cannot (yet) write the code on a running system. But there is one thing you can do to improve your work – you can create your own administrator’s terminal.

The module is created using IronPython – a .NET python engine that can intergrate with your application. Maybe it’s not your favourite C# (or VB etc.) but it’s still close to your application/domain logic and for sure more fiendly than dealing with underlying data with SQL. Python is very programmer-friendly language. You need to get through the basic syntax and for the rest of the time you only use your API in a way you know from the source code.

You may think that creating such a terminal could be a hard work but it’s not. To achieve the goal you need to implement a mechanism, that takes a script from the user and gives the result of the script execution. In other words you need to imlement an interface like that:

public interface IScriptExecutor
{

//Execute IronPython code
string ExecuteScript(string script);

//Bind .NET objects to IronPython variables
void BindVariable(string key, object value);
}

With the IronPython library it is really simple. The complete source code of the script engine is presented below.

public class ScriptExecutor: IScriptExecutor
{
     private readonly ScriptEngine engine;
     private readonly ScriptScope scope;
     public ScriptExecutor()
     {
         this.engine = IronPython.Hosting.Python.CreateEngine();
         this.scope = this.engine.CreateScope();
     }

     public void BindVariable(string key, object value)
     {
           this.scope.SetVariable(key, value);
     }

     public string ExecuteScript(string script)
     {
         try
         {
             var scriptResult = this.engine
                     .CreateScriptSourceFromString(script, SourceCodeKind.AutoDetect)
                     .Execute(this.scope);
             return scriptResult != null ? scriptResult.ToString() : null;
         }
         catch (Exception e)
         {
             return e.Message;
         }
     }
 }

To use it you need to download mentioned IronPython framework. It’s kind a heavy library, especially if we use only three DLL’s: IronPython, Microsoft.Dynamic, Microsoft.Scripting.

In the constructor we initialize the PythonEngine. You can also bind some variables to the Python engine if you need. The most important method is of cource ExecuteScript where the most difficult thing is to obtain feedback from the python engine.

Let’s mix it together.

Now you can use the ScriptExecutor to create your administrator console. Because you use dependency injection, you probably have a static ServiceLocator (or something like that; if it’s not static you can bind it a proper container using BindVariable() method). Thus you have an access to each module you got in the application. Do you want to count the ‘Customer’ entities?

ServiceLocator.Resolve[ICustomerRepository]().GetAll().Count

Do you want to use your logic to create a new entity? Ok.

import clr
clr.AddReference("WebIronPythonConsole")
from WebIronPythonConsole.Domain import *
from WebIronPythonConsole.Infrastructure import *
repository = ServiceLocator.Resolve[IToDoItemsRepository]()

newItem = ToDoItem()
newItem.Name = 'Added by ironpython'
newItem.IsDone = False
repository.Add(newItem)

To get better the python language you may need some tips:

  1. Whitespaces are important
  2. When you need to work with generic method/classes, use [] istead of <>
  3. Lamba expressions are also called lambdas:

         C#: x => x.Contains("hello")

         Python: lambda x: x.Contains("hello")

  4. To use LINQ you need to import System.Linq from System.Core (see the code below)
  5. import clr
    clr.AddReference("System.Core")
    clr.AddReference("WebIronPythonConsole")
    from System.Linq import Enumerable
    from WebIronPythonConsole.Domain import *
    from WebIronPythonConsole.Infrastructure import *
    repository = ServiceLocator.Resolve[IToDoItemsRepository]()
    result = Enumerable.Where(repository , lambda x: x.Name.Contains("MyTask"))
    
    

Download

Feel free to play with an example application: WebIronPythonConsole.zip

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s