got net?

Kevin Hazzard's Brain Spigot

About the author

Welcome to Kevin Hazzard's blog.
E-mail me Send mail

Recent comments

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2009

Mixing Static and Dynamic .NET Languages for Philly Code Camp 2008.3

I presented at the Philly Code Camp on 11 October 2008 for a group of about 20 developers. Thanks to all who came out to listen to my presentation. And thanks especially to Don Demsak (donxml) for attending and really helping me to shape the talk. Don added a lot of anecdotal information that I would not have included on my own. It was a very fluid discussion with lots of give and take. When I give this talk again at the Raleigh Code Camp in November 2008, the folks who attend will benefit from what happened in Philly.

The gist of this presentation is that it's possible to mix the Dynamic Language Runtime (DLR) into statically-typed, early-bound languages like C# to make them much more flexible. In this talk, I demonstrated how a ShoppingCart being filled with Products can adjust discount rates based on marketing rules written in an external Domain Specific Language (DSL). In this case, my DSL was really just Python. I chose to use Python because the syntax is so simple and clean. It's so light, it doesn't get in the way. It's not a real DSL, of course, but by injecting .NET objects into a ScriptScope on a ScriptRuntime (all DLR hosting terms), the Python syntax acting on those injected types looks an awful lot like a language for managing product discounts.

The few slides I had and the source code are linked below. For this code, I used IronPython 2.0 Beta 5. You will need to download and install IronPython to compile the code.

MixingStaticAndDynamicDotNETLanguages20081011.pptx (91.66 kb)

MixingStaticAndDynamicDotNetLanguages20081011.zip (16.65 kb)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by kevin on Saturday, October 11, 2008 3:58 PM
Permalink | Comments (0) | Post RSSRSS comment feed

July 2008 Richmond Meet and Code Notes

The Richmond Meet and Code Dinner in Richmond tonight was awesome. We had 30+ people turn out. Our key presenter had to cancel at the very last moment but Justin Etheredge stepped up to the plate and pitted his self-proclaimed meager Ruby skills against the barrage of questions from the crowd. Justin did a great job, nascent Ruby skills or not. Harper Trow also presented on the history and current state of Ruby and man, I've so been looking forward to that! Harper was just great. I sure hope he steps out and presents more often. Harper's whole life experience oozes with "I love .NET and I love everything else, too." We need more of that kind of healthy alternative-yet-embracing thinking in the .NET community I believe.

The Meet and Code Dinner format is excellent, in my opinion. I think what Justin is doing is commendable. The goal of his group is to build up the community, not potential sponsors. He's going to be setting up a website and taking donations via PayPal. I am definitely going to support him financially in his effort.

In between two of Justin's sessions, I presented my ProxyGen tool again. This is the same tool that I presented at the last Richmond .NET Code Camp and at the last NOVA .NET Code Camp. Except this time, I focused not on the task of dynamic proxy generation against WSDL contracts but on the use of the ScriptRuntime and ScriptScope classes in Microsoft.Scripting to host a Python or Ruby scripting engine within a C# application. I think I got the brains of the attendees pumping with ideas which is all I was after. I described an application that could be statically typed and early bound, written in C# with a dynamic lower edge that could be scripted from a remote source. People in the crowd started coming up with all sorts of great ideas to implement business logic in dynamic code and inject it. Awesome thinking!

I've attached the latest build of the ProxyGen code below. Here are a couple of screenshots that show how it works. This first screen shot shows running IPY.EXE to execute a Python script to call a SOAP-based web service with no precompiled proxy. The only magic here is in some dynamic code generation that my ProxyForWsdl class does by downloading the WSDL contract and building classes for services, operations and data contracts. As you can see, I am calling an integer factoring service dynamically. No new Python knowledge yet. But read on.

The next screen shot is of the test harness in the sample code showing how a Python script similar to the one shown in IPY.EXE above can be injected into a C# application.

The C# code to embed the Python engine is simpler than you would think. I wrote a little wrapper class to make it easier to digest:

using System.Collections.Generic;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;

namespace TestHarness
{
    public class DynEngine
    {
        private readonly ScriptEngine _engine;
        private readonly ScriptScope _scope;

        public DynEngine( string engine )
        {
            // get an engine from the script runtime of
            // the desired type
            _engine = ScriptRuntime.Create().GetEngine(engine);

            // creating a scope gives us a dynamic space
            // to run code in
            _scope = _engine.CreateScope();
        }

        public T ExecuteStatements<T>( string codeText,
            string resultVarName,
            IEnumerable<KeyValuePair<string, object>> scriptVars)
        {
            // inject some variables into the scope
            foreach (var kvp in scriptVars)
                _scope.SetVariable(kvp.Key, kvp.Value);

            // "compile" the code and execute it
            var source = _engine.CreateScriptSourceFromString(
                codeText, SourceCodeKind.Statements);
            source.Execute(_scope);

            // pull a typed variable from the scope as the result
            return _scope.GetVariable<T>(resultVarName);
        }

    }
}

Invoking the Python code is as easy as loading up variables into a dictionary, instantiating my wrapper class with the type "py" for Python and calling ExecuteStatements with the Python source code text:

var vars = new Dictionary<string, object>
           {
              { "url", tbUrl.Text },
              { "ep", ep }
           };

var engine = new DynEngine( "py" );
result = (List<int>)engine.ExecuteStatements<object>(
   tbPythonCode.Text, tbEvaluationExpression.Text, vars );

The HTTP path to the web service WSDL contract is passed as a parameter by injecting it as a script variable named url in the Python script. And the ServiceEndpoint is also injected as a variable named ep so that it's Name property can be selected in the Python script. This is a good example of marshalling a .NET object into the script scope where it can be fully discovered and used by a dynamic language. In the DynEngine class shown above, you can see the SetVariable and GetVariable methods on the ScriptScope being used to inject and extract variables as a type of Inter-Process Communication (IPC) mechanism. This isn't the only way to communicate between a host and a dynamic script but it's simple for illustration purposes.

That's pretty much it. Hosting a dynamic Python in C# is not hard at all. In fact, if I referenced the IronRuby assemblies on the TestHarness project, I could switch the "py" constructor parameter to the DynEngine shown above to "rb" and inject Ruby script just as easily. That's literally all we would have to do to move from Python to Ruby in this case. As we used to say in America in the 1980s, that's tasty!

The ProxyGen code's attached below. Be sure to download the IronPython distribution from CodePlex and reference four (4) assemblies in the TestHarness project. I am using IronPython 2.0 Beta 3, by the way. These are the four (4) IronPython assemblies you'll need to reference:

  • IronPython.dll
  • IronPython.Modules.dll
  • Microsoft.Scripting.dll
  • Microsoft.Scripting.Core.dll

All of them can be found in the root of the IronPython BIN distribution ZIP. Here's the ProxyGen code I demoed at the meeting.

ProxyGen20080731.zip (21.40 kb)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by kevin on Thursday, July 31, 2008 10:18 PM
Permalink | Comments (3) | Post RSSRSS comment feed