View Single Post
Old 02-01-2008   #5 (permalink)
thoward37


 
 

Re: Hosting Powershell in App - Obtaining delegates to powershellfunctions

On Feb 1, 10:20*am, "Oisin (x0n) Grehan [MVP]" <ois...@xxxxxx>
wrote:
Quote:

> On Jan 31, 11:39*pm, thoward37 <thowar...@xxxxxx> wrote:
>
>
>
>
>
Quote:

> > Hi all, this is a follow-up to an earlier post I made regarding
> > embedded Powershell:
>>
Quote:

> > In short, I'm hosting Powershell in an app as part of a rules engine,
> > using it to repeatedly execute user defined scripts on data provided
> > from a database, as one kind of "rule".
>
Quote:

> > The way I initially implemented it was to create a single runspace,
> > then create and execute a new pipeline eachtime I needed to execute
> > the Powershell rule.
>
Quote:

> > An example rule looks like this:
>
Quote:

> > $dataValue =
> > $dataProviders[""SomeRandomSqlData""].GetValue(""SomeValue"");
> > $checkValue = $dataProviders[""StaticData""].GetValue(""MaxValue"");
> > if ($dataValue -eq $checkValue) { exit 5 } else { exit 0 }
>
Quote:

> > The variable $dataProviders is a dictionary containing various data
> > providers that allow the Powershell script to make some decisions
> > about some data. It is passed into the Powershell world using a
> > statement like ...
> > Runspace.SessionStateProxy.SetVariable("dataProviders",
> > dataProviders); ... and it's updated each time I execute a pipeline
> > with the currently available data.
>
Quote:

> > The exit code of the pipeline is checked to get the result of the
> > rule, which is then evaluated by the rest of the rule engine.
>
Quote:

> > So, my previous post I had asked about ways to re-use a single
> > pipeline, instead of instantiating a new one everytime, but found that
> > was not possible.
>
Quote:

> > Currently, this implementation works, but it's very slow, and there
> > are other options available for them to script in via traditional .Net
> > languages. Also, this code isn't even in QA at the moment, much less
> > released, so it's still a good time to make changes in the design...
>
Quote:

> > Since then, it occured to me that a better way to do this might be as
> > such:
>
Quote:

> > 1. Instantiate Runspace
> > 2. Pre-load the scripts into the Runspace. Each script defines a
> > function for each Powershell rule I'll need to run. The function takes
> > the dataProviders variable as a parameter, and returns an integer.
> > 3. Obtain delegates to the loaded functions from the Runspace.
> > 4. When the rule needs to be executed, just invoke the delegate from
> > my C# code.
>
Quote:

> > My intention for getting the delegate to the PS function was to use
> > the get-delegate function described here:
>>
Quote:

> > So the c# delegate defintion would look like:
>
Quote:

> > * public delegate int PsRuleDelegate(IDictionary<string,
> > IRuleDataProvider> dataProviders);
>
Quote:

> > The user function delegate creation code would look like this (with
> > each script definition getting it's own delegate variable):
>
Quote:

> > * .. insert get-delegate code here ..
>
Quote:

> > * $MyRuleDelegate = get-delegate `
> > * My.Namespace.PsRuleDelegate *{
> > * * * $dataValue =
> > $dataProviders[""SomeRandomSqlData""].GetValue(""SomeValue"");
> > * * * $checkValue =
> > $dataProviders[""StaticData""].GetValue(""MaxValue"");
> > * * * if ($dataValue -eq $checkValue) { return 5 } else { return 0}
> > * }
>
Quote:

> > Getting the delegate back from the runspace would look like:
>
Quote:

> > * Runspace.SessionStateProxy.GetVariable("MyRuleDelegate");
>
Quote:

> > So, before I go fiddling with it, and trying to make that happen...
> > I'd like to know, is this a viable solution? Will this work? I'll
> > probably try it anyway tomorrow, but I'd like to hear what more
> > experienced and knowledgable people have to say about this idea.
>
Quote:

> > I'm guessing that I will need to assemble the delgate creation
> > function, and all the rule function definitions into a single script,
> > which is loaded when the runspace first starts up, then obtain the
> > named delegate variables after the runspace loads. Would I then not
> > need to run a pipeline? Could those delegates be called directly from
> > my C# code without an active pipeline (but with an active runspace?).
>
Quote:

> > I think that would improve the performance considerably, without
> > changing too much of what the end user needs to write.
>
Quote:

> > Thanks,
> > Troy
>
> Hi Troy,
>
> From my understanding of the powershell engine itself, it won't be
> possible to get a delegate to a function as such. PowerShell's script
> is interpreted and no matter how you invoke it, the creation of a
> pipeline to execute it is implicit.
>
> Don't get me wrong though, PowerShell is one of the greatest things
> (imho) to come out of Microsoft in the last few years but it truely is
> a prototype in the best sense of the word; a proof of concept that has
> shown itself to be a resounding success in all the areas of
> application it has found itself. We all expect great things from V2 -
> an incremental improvement in fuctionality in tandem with a order of
> magnitude increase in speed would be a great result I think. The
> community has proven itself to be more than capable of filling in the
> missing bits (thanks to the excellent extensibility of the product),
> but as for core efficiency and speed, well, that's down to Jeffrey's
> great team.
>
> - Oisin- Hide quoted text -
>
> - Show quoted text -


Yes, you're right.

I took a tour through the Powershell source using Reflector. There is
no tangible advantage to doing it the way I described. I assumed that
under-the-hood, Powershell functions are compiled at some point, even
if only "on the fly"... But it looks like they are not, so by doing it
the way I described, it's just a more complicated way to achieve the
same results... I might be able to avoid some parsing over-head, but
that's about all. Not sure that's worth making the code more
complicated...

Ah well. So much for what seemed to be a good idea.

Thanks,
Troy
My System SpecsSystem Spec