Saturday 16 April 2011

System.Net.HttpWebRequest and PowerShell, part 2

In the last post, we covered making a basic web submission and getting a response back using .NET and Powershell.  This is all fine and dandy, but without interpreting this data, you'll find yourself unable to postback to the application to login.

Sadly, .NET has no simple way inbuilt (without third party modules) to parse HTML into a tree structure capable of being easily navigated to extract information.  Again, if you were using InternetExplorer.Application, this provides an interface onto the DOM, but this does not allow you full control of the process of downloading data, which is what we're after here.  Its also extraordinarily slow: using Measure-Object, you can determine that parsing the innerHTML of an element using regular expressions can be from 10-20 times faster than returning  the row and column objects via the API and iterating over their innerText.

So let's assume we're using regular expressions.  How do we go about this?

Consider the following regular expression:
$r=[regex] "<($([String]::join('|',$tagnames)))((.|\n)+?)>"

Given an array $tagnames, we match an element that is any one of these tagnames, followed by the shortest possible number of characters, and then a closing right angled bracket.  This does not match (a) elements that are syntactically incorrect or (b) elements that do not have any attributes.

We can then extract the attributes via the following regular expression:
$r2=[regex] '((\s|\n)+)(\w+)=("[^"]*?"|[^\s]+)';

This extracts from the second match group of the first regular expression, the name and value pairs that constitute attributes.  They can be enclosed in quotes, or be a run of characters not containing a space.  You can abstract this to include the single quote as a valid enclosing character as well, I leave this as an exercise to you.

Lets suppose we want to extract all the input tags (including input type=hidden), filter them, and post some of then back to the application.  Tags such as __VIEWSTATE and other ones beginning with underscores are a good example of this.  They need to be transmitted with the session state cookie (which is not easily extracted from IE itself, but is easily gotten via System.Net.HTTPWebRequest)  in order to retain our login session.   Using these regular expressions and iterating the matches from the second will allow us to extract the name/value/type fields and extract them as required, prior to  posting them back.

So how do we post them back to the form?  Well, a post request needs to send data representing the post request to the server, and the data must be url encoded.

$pdata=[String]::Join('&',@($namevaluepairs|%{"$($_.name)=$([system.web.httputility]::UrlEncode($_.value))";}));

The above translates an array of hashrefs containing name,value pairs, into post data.  Note that you must first:
[System.Reflection.Assembly]::LoadWithPartialName("System.Web");

in order to load the assembly containing the UrlEncode function.

Finally, you must translate the data of the post request to the appropriate character encoding, and post it off.  Here is an example of that translation:

$bytez=[System.Text.Encoding]::UTF8.GetBytes($pdata);

This is translating the string $pdata into a byte array representing the string in the UTF8 character encoding (that most commonly used by web servers).

Finally, you must let the server know how much data you will be sending, so it can allocate memory for your request, as well as telling it what format the data is in:


    $req.ContentType = "application/x-www-form-urlencoded";
    $req.ContentLength = $bytez.Length;
    $reqstream = $req.GetRequestStream();
    $reqstream.Write($bytez, 0, $bytez.Length);
    $reqstream.Close();


This completes your postback to the server and you now read back the data in the usual way (described in part 1).

Now you can check the results of your download and react in your program accordingly, saving the file or textual data to an appropriate location.

Wednesday 13 April 2011

System.Net.HttpWebRequest and PowerShell, part 1

Consider this scenario: You have a system written in .NET which produces reports in some well defined format: Excel, Access, etc.  To download these files, you fire up an IE window via the Internet.Application API, login to the application, navigate to the report and use the Click() method of the Button or Image element to fire off a post request.  This ensures that the hidden fields a .NET application may produce, such as the VIEWSTATE, as well as cookies, are preserved.

This works well, with the caveat that the user of the machine gets prompted for where to save this file.  You want to automate the download of the file to save it in an already defined location, to save the time waiting for the user to save the file and close the window.

You check the documentation for IE's automation API, only wind up disappointed.  You cannot automate the saving of the file via the InternetExplorer.Application interface, or any other interface that allows access to the mshtml API.  What then to do?

Well, luckily Microsoft's .NET API contains a class known as System.Net.HttpWebRequest, which allows you to send GET or POST requests to a server, and to manage cookies.  So if you can parse the HTML returned by this API, and extract the hidden input fields described above to repost to the server, you can read back the file that the server returns and save it.

To do this in Powershell however, requires some understanding of .NET. Lets take a look at a simple function to return a HTML response from a server.

function Get-HTML-Response {
  param($uri,$cookiejar);
  $req=[System.Net.HTTPWebRequest]::Create($uri);
  $req.CookieContainer=New-Object System.Net.CookieContainer;
  $req.Method='GET';
  if ($cookiejar -ne $null) {
    $req.CookieContainer=$cookiejar;
  }
  $req.UserAgent='Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)';
  $resp=$req.GetResponse();
  $strm=$resp.GetResponseStream();
  $sr=New-Object System.IO.Streamreader($strm);
  $output=$sr.ReadToEnd();
  return @($req,$resp,$output);
}

The .NET 2.0 API allows you to create a HTTPWebRequest object directly from a URI via the Create method.  All we need to do is setup the User-Agent, method, and cookie store; then read back the response and return all the information to our script.

Note that this function does not deal with exception handling... if you want to do this (and you should care about exception handling), the documentation for the exceptions the above functions can return are available via the MSDN website.

To ensure that we can provide continuity between requests, we provide the option to pass a CookieContainer containing Session Info to the function, to communicate through to the server.

The response returned by GetResponse contains header information, including the status code returned by posting to the server.  You'll want to check this to ensure 200/OK status.  The request object's cookies are automatically updated by the process of submitting the request and returning the response.

Calling GetResponseStream on the request object, on checking it for consistency, will return a Stream object containing any textual output from the server (the server response or page content).  You  need to read this stream in using a Streamreader object or pass the stream to some other object that will deal with the information contained in it.  In this instance, we just return the output.

In the next installment, I'll discuss POST requests, and finally, HTML parsing and interpretation of the data.

Monday 11 April 2011

Creating Styles with Storyboard Animation in Powershell

Here is an example of an event trigger which animates the color of a textbox on the MouseEnter event firing.

$trigger1=New-Object Windows.Eventtrigger([Windows.Controls.Textbox]::MouseEnterEvent);
$trigger1.Actions.Add((New-Object windows.Media.Animation.BeginStoryBoard));
$bsbitem=$trigger1.Actions.Item(0);
$bsbitem.StoryBoard=New-Object windows.Media.Animation.StoryBoard;
$bsbitem.StoryBoard.Children.Add((New-Object windows.media.animation.coloranimation([Windows.Media.Colors]::LightBlue,[Timespan]::FromSeconds(1))));
[Windows.Media.Animation.StoryBoard]::SetTargetProperty($bsbitem.StoryBoard.Children.Item(0),[Windows.PropertyPath] "Background.Color");
$styletxtbox.Triggers.Add($trigger1);

Several things should be noted:
  1. You create the EventTrigger using the associated event from the type you are animating.
  2. $styletxtbox is a Windows.Style object.
  3. The trigger events mouse be events derived from Windows.TriggerAction.  This means they must be either wrappers for a Storyboard, or a SoundPlayerAction.  You can use Keyframes to quickly change a color, or use the smooth transitions defined in the inheritance hierarchy for Windows.Media.Animation.Animationtimeline
  4. Set the property operated on  via [Windows.Media.Animation.StoryBoard]::SetTargetProperty.
The question might be raised, why not just use XAML and save yourself all the trouble?  Well, there are several answers to that, most of which focus around.
  • The wastefulness of dynamically generating XAML code for a dynamic form, parsing it and creating the objects VS just creating or manipulating the objects involved directly.
  • The capacity to easily reference every one of the elements of the form as a variable, for instance in writing event handlers.
The key here is to understand when it is necessary to use either declarative or procedural methodologies in evolving the objects.  Dynamic flexible data calls either for procedural design, or data templating, whichever fits more with your design methodology.  WPF supports both.

Sunday 10 April 2011

Raison d'ĂȘtre

  • LiveJournal is dead.  Long live LiveJournal!
  • Facebook is facile, and unsuited to deep conversation.  Your actions are on display.
My reasons for starting this blog are varied. The first is philanthropic, to the programming community at large. I've been a programmer, system administrator or customer support person since 1998, on and off in various positions. What I've learned about programming, interface design, and the pros and cons of different programming methodologies during this time has helped me evolve... from the small intricacies of Perl/CGI based programming in the earlier years, to fully fledged timer driven UI-design in .NET.  I want to share some of the painful experiences and revelations based on experience I've had since starting this path, as there is a lack of information on particular topics in the area for instance of WPF based design, Windows Forms, Silverlight and so on.

I come originally from a Linux background, but as a programmer I have found the most joy in the abstraction that Powershell and the various Windows Interop DLLs presents to me.  Why?  Nothing that I am aware of in the Unix environment at present allows such a level of integration between existing programs and scripts, to the extent that one can cut and paste data from a spreadsheet to an automatically created email in 5 lines or less of code.  Microsoft it seems, made a very wise business decision in providing the level of abstraction they have in their products, such as Word, Outlook and Excel, as well as Access.  The ability of programs to access well defined API's to create Word documents, interact with Outlook's calendar or mail merge faculties, and more, when combined with the .NET based scripting which Powershell provides, presents to the programmer:
  • Rapid development based on models including extreme programming and functional programming.
  • The ability to abstract the development process and allow for easy customization of a UI via text  (whether in centralized INI files or the registry).
Why is this so important?  Well, for one it makes for a rapid development lifecycle, the ability to test code straight from the command line without need for lengthy recompilations of code.  Powershell's seamless ability to create background runspaces in CTP2 means the ability to create multithreaded, responsive applications.  Secondly, it means abstraction, along the lines of that abstraction which LISP originally provided in the early days of Unix.  Powershell's Invoke-Expression, as well as its quick access to function definitions direct within the environment, when combined with easy GUI design, makes it possible to embed REPL's within code for ease of testing and debugging.   It even makes it possible for Powershell code to write, test and then save or edit code in a language, in short, to create an IDE within the language itself, in a very small number of lines, to enhance the already formidable powers of the ISE.  Scenarios such as that seen in the movie Swordfish start coming out of the realm of fiction and into the realm of quite possible FACT.

So that is one reason for the creation of this blog - the exploration of how to go from 0 to 360 in the realm of GUI based programming in this area, within months.  At times I may also discuss topics that are best described as philosophical... the connections between abstraction and evolution, pros and cons of different types of abstraction, perhaps even futurist topics (or their nemesis, survivalism).  The topic is anything that interests me, and if you don't like a post, you don't have to read it.  Thats the beauty of free-will.

I have many interests, but this one will be mainly restricted to programming, abstraction, and topics related to evolution (especially as it relates to continuum or catastrophe theory).

With that in mind, lets begin!