 Wednesday, August 12, 2009
So I decided to take the Horn project for a test drive after repaving a number of machines to Windows 7 RTM and waiting for things to install. After Horn’s initial announcement this year I was excited, but it didn’t really do anything at that stage (and I didn’t have enough time to assist with the dev work / patches)... so I put it on the back burner. But I found myself need to rebuild Rhino Tools, Castle and NHibernate today from trunk and thought I would give it a try.
At any rate, this is a post covering my “noob” observations as I walk through building horn, and then using horn to build Rhino Tools. Background As a little background, Horn was started by the Scotland ALT.Net group, it was kicked off on the scotaltdotnet google code project, and later moved to the hornget project, also on google code. The projects Initial mission statement is to “take control of building a common set of open source packages that are probably similar to many in the ALT.NET space” which I think it’s coming close to realising, but they also have a grander vision of “providing a standard mechanism for easy installation of .Net Packages” – something I definitely think .Net needs, and that dynamic languages lord over us currently with their gem’s and egg’s (and incidentally it is a much trickier problem to solve when you need to produce compiled assemblies, think signing vs. unsigned, ability to specify x86/x64/any platform flags and the way in which assembly versioning in .Net works). Building Horn Assuming you have the Subversion command line tools installed (or tortoise svn) - it’s pretty easy. First off check out the horn trunk… svn checkout http://hornget.googlecode.com/svn/trunk/ hornget-read-only
Once all the files have been pulled down, you need to then build horn, using the following batch file: cd hornget-read-only\src
hornbuild.bat
hornbuild.bat will execute Nant, and the total build takes about 15 to 20 seconds. It dumps the outputs into a \build\net-3.5\debug\ folder, including horn.exe which is the command line client (Horn package manager). I would assume as Horn matures we will see an installer / binary release on the horn website, which should hopefully make this even easier.
Running Horn
Now jump into the outputs directory...and run horn for the first time. cd build\net-3.5\debug\
horn
At which point you will be rewarded with the usage screen: THE HORN PACKAGE MANAGER
http://code.google.com/p/hornget/
Usage : horn -install:
Options :
-rebuildonly Do not check for the latest source code.
-version: The specific version of a package.
Now it's just a matter of building the project you want.. in this case let's build rhino tools (which in turn will build Nhibernate and some parts of the castle project). Might pay to go make a coffee at this point, as there's going to be a lot going on while you wait patiently. horn -install:rhino
Oh, and expect to see a lot of this if your connection to the various project’s SVN repositories is slow.. Reading the current revision for castle
working......
working......
working......
working......
working......
working......
working......
working......
working......
working......
Also, as an aside - there's a cyclic relationship between Castle and NHibernate (i.e. Nhibernate relies on Castle Core & Dynamic Proxy, while Castle relies on NHibernate to build) - it's not truly cyclic as such though, just that if you attempt to build either set of project in it's entirety, you will need the outputs of the other. In Horn things like dynamic proxy are broken out into separate projects ie. "castle.tools" rather then just "castle" (though a castle package exists as well, which does build castle in it’s entirety).
It seems to handle this scenario well, and this was certainly a failing of most home-grown solutions I’ve put together over the years which relied on nant or msbuild files… Right, so after about 5 minutes, you should see the horn executable run to completion, like this: BUILD SUCCEEDED
Total time: 46.6 seconds.
HORN HAS FINISHED INSTALLING rhino.
Note: The "BUILD SUCCEEDED" message is from rhino tools, which was the last project to be built, rather then telling us how long the process took in total. Locating OutputsAt this point Horn has finished doing it's job, but... if you do a quick directory search, you probably won't find any output binaries. What gives? Well Horn in fact stores all it's files under a directory against the user's profile. So in the case of windows 7 / Vista, that means I can just change directory to find them: c:\dev\OtherOpenSource\hornget-read-only\src\build\net-3.5\debug>cd %USERPROFILE%\.horn
C:\Users\alex\.horn>_ If we grab a quick directory listing... we can see there's a few folders in there. C:\Users\alex\.horn>dir * /A
Volume in drive C has no label.
Volume Serial Number is 6AFA-976C
Directory of C:\Users\alex\.horn
12/08/2009 09:39 p.m. <DIR> .
12/08/2009 09:39 p.m. <DIR> ..
12/08/2009 09:37 p.m. <DIR> .svn
10/08/2009 03:47 p.m. <DIR> buildengines
10/08/2009 03:47 p.m. <DIR> builders
10/08/2009 03:47 p.m. <DIR> esbs
10/08/2009 03:46 p.m. <DIR> frameworks
10/08/2009 03:47 p.m. <DIR> ioc
10/08/2009 03:46 p.m. <DIR> languages
10/08/2009 03:46 p.m. <DIR> loggers
10/08/2009 03:46 p.m. <DIR> mappers
10/08/2009 03:47 p.m. <DIR> mocks
10/08/2009 03:47 p.m. <DIR> orm
12/08/2009 09:45 p.m. <DIR> result
12/08/2009 09:37 p.m. 15 revision.horn
10/08/2009 03:47 p.m. <DIR> web
10/08/2009 03:47 p.m. <DIR> wpf
1 File(s) 15 bytes
16 Dir(s) 578,876,366,848 bytes free
Notice the .svn folder, the .horn directory is actually populated from this subversion repository, which stores all the package descriptions etc. (I’m not entirely clear on the terminology here, documentation is fairly sparse on the website – they’re almost more like package build scripts, because they’re a DSL outlining the steps required to build the outputs, required dependencies and so on).
The one folder not under version control is "result" - which is where our outputs are actually stored. So let's take a quick look... C:\Users\alex\.horn>cd result
C:\Users\alex\.horn\result>dir
Volume in drive C has no label.
Volume Serial Number is 6AFA-976C
Directory of C:\Users\alex\.horn\result
12/08/2009 09:45 p.m. <DIR> .
12/08/2009 09:45 p.m. <DIR> ..
10/08/2009 03:56 p.m. 1,997 ABC.hbm.xml
10/08/2009 03:48 p.m. 110,592 adodb.dll
10/08/2009 04:07 p.m. 568 AnotherBus.config
10/08/2009 03:48 p.m. 40,960 anrControls.Markdown.NET.dll
10/08/2009 03:58 p.m. 106,496 antlr.runtime.dll
10/08/2009 04:01 p.m. 116,736 Antlr3.Runtime.dll
10/08/2009 03:59 p.m. 40,960 Bamboo.Prevalence.dll
10/08/2009 03:59 p.m. 6,656 Bamboo.Prevalence.Util.dll
10/08/2009 04:01 p.m. 40,960 Boo.Lang.CodeDom.dll
10/08/2009 04:01 p.m. 753,664 Boo.Lang.Compiler.dll
10/08/2009 04:01 p.m. 118,784 Boo.Lang.dll
10/08/2009 04:01 p.m. 32,768 Boo.Lang.Extensions.dll
10/08/2009 04:01 p.m. 86,016 Boo.Lang.Interpreter.dll
10/08/2009 04:01 p.m. 425,984 Boo.Lang.Parser.dll
10/08/2009 03:48 p.m. 28,672 Boo.Lang.PatternMatching.dll
10/08/2009 04:01 p.m. 81,920 Boo.Lang.Useful.dll
10/08/2009 04:01 p.m. 32,768 Boo.Microsoft.Build.Tasks.dll
10/08/2009 04:01 p.m. 28,672 Boo.NAnt.Tasks.dll
10/08/2009 04:07 p.m. 393 BusOnTransactionalQueue.config
10/08/2009 04:07 p.m. 405 BusWithLogging.config
10/08/2009 03:48 p.m. 45,056 Cassini.dll
12/08/2009 09:43 p.m. 249,856 Castle.ActiveRecord.dll
12/08/2009 09:43 p.m. 6,656 Castle.ActiveRecord.Linq.dll
12/08/2009 09:43 p.m. 17,920 Castle.ActiveRecord.Linq.pdb
12/08/2009 09:43 p.m. 4,736 Castle.ActiveRecord.Linq.xml
12/08/2009 09:43 p.m. 960,000 Castle.ActiveRecord.pdb
10/08/2009 04:02 p.m. 543,085 Castle.ActiveRecord.XML
12/08/2009 09:42 p.m. 49,152 Castle.Components.Binder.dll
12/08/2009 09:42 p.m. 138,752 Castle.Components.Binder.pdb
12/08/2009 09:42 p.m. 17,275 Castle.Components.Binder.xml
... And the list goes ...
353 File(s) 67,002,734 bytes
2 Dir(s) 578,875,887,616 bytes freeNot bad for what was effectively just a single command line. Where to from hereI strongly suggest giving Horn a go – not just because it’s useful, but I think that it fills a real hole in the .Net developer open source space, removing one of the barriers to entry – making it easier for people to develop applications against the trunk, or a specific version, of many popular open source projects, will definitely drive up adoption of these projects.
It’s worth noting that currently “Horn” is considered a “developer-only” release at the moment, though I think it’s current state is useful enough to warrant giving it a try, and providing feedback to the Horn dev team etc. so umm… Check it out, if you haven’t already. I think you’ll be pleasantly surprised.
 Monday, November 17, 2008
Cibrax (Pablo M Cibrano) - has supplied an example WCF Provider sample, including a generic Request Interceptor suitable for OAuth enabling your own RESTful WCF services. The code is available in these two new projects (as part of the DevDefined.OAuth library). The implementation has been covered on his blog here in a couple of posts: Thanks for the contribution Cibrax - much appreciated! Take a look at the devdefined-tools site for more details on this library, and for those who are curious this code is all released under the MIT license.
 Monday, November 10, 2008
 Just a quick reminder, as I had a brief call with Paul Lo (from Microsoft) this morning and they haven't really got enough attendees in Auckland (come on Auckland, when will we shake off our developer apathy from the last couple of years?!) More details hereThere is swag too (but that's not a good reason to attend of course). I'm going to be at Session 6 (11:00am onwards) so hopefully I'll see some of you there.
 Monday, September 22, 2008
I've had some requests from different ASP.Net developers writing applications for the OpenSocial platform lately wanting to use DevDefined.OAuth to validate signed requests with a public certificate - so I've put together a little example to help get people started. What are we trying to do?So first of let's review how the process works and what we're trying to achieve.  Basically as a developer for the OpenSocial platform you will be writing gadgets - these gadgets are generally defined in an XML document providing information about your application and a chunk of html content which will be rendered into an IFrame to kick the application off (including javascript functions etc. to fetch remote content) - to work around spoofing issues and to avoid cross-scripting issues your gadget can use pre-canned functions in the open-social java-script library to make requests to your own services, which to the developer appear to be a direct request to their site. Under the hood the the requests are instead made to the opensocial host platform, which acts as a proxy passing the request onto your application - at this point the platform employes OAuth (though without any 3-pronged delegate authority being established) to sign the request using a x509 Certificate (i.e. the RSA-SHA1 signature method) at which point it calls your application with the signed request and passed on response back to the calling gadget. The main goals in signing the request (in so far as I can tell) are to ensure it hasn't been tampered with, spoofed and provide a Nonce and timestamp so you can void replay attacks - something that using SSL alone would not prevent. Because a lot of the mechanics of OAuth itself is being circumnavigated, it's much simpler to verify the signature is valid. Gadget XMLRight - onto the code - Let's take a look at the Gadget XML first:
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="OAuth TestBed" description="Testbed to test the OAuth library"
title_url="http://www.devdefined.com/" author="Alex Henderson" author_email="bittercoder@gmail.com" author_affiliation="friendster" author_location="Auckland, New Zealand" thumbnail="" icon="">
<Icon></Icon>
<Locale lang="en" />
<Require feature="opensocial-0.7" />
<Require feature="dynamic-height"/>
<Require feature="views"/>
</ModulePrefs>
<Content type="html">
<![CDATA[
<script>
function makeRequest(server_url,fn){
var params = {};
params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET;
params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.TEXT;
params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.SIGNED;
gadgets.io.makeRequest(server_url, fn, params);
}
function renderPage(){
var url = 'http://demo.devdefined.com/Friendster/SocialService.aspx';
makeRequest(url, pageload_Callback);
}
function pageload_Callback(data) {
var response;
if(data.text){response = data.text;}else if(data.body){response = data.body;}else{response = data;}
if(response.indexOf){
document.getElementById('container').innerHTML = response;
}
}
gadgets.util.registerOnLoadHandler(function() {
renderPage();
});
</script>
<div id="container">
</div>
]]>
</Content>
</Module>
Basically the XML for the gadget is a chunk of metadata and finally some actual content for the gadget itself - notice that it regsters a handler to run on load of the gadget, and that it's then making a request to the url http://demo.devdefined.com/Friendster/SocialService.aspx and render the response in the inner HTML of the container div DOM element. The key to this being an OAuth signed request is the 5 th line of the makeRequest function: params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.SIGNED;
So far so good - uploading your application is pretty easy - but is generally platform specific - if you wanted to try this out on Friendster then just head to http://www.friendster.com/developer/ click on the OpenSocial tab and follow the instructions - the approach is to save your gadget definition as an XML file somewhere, then publish that XML document on the web and then create an application in your open social host of choice and direct th it to the XML files location. It takes all of a minute to do.
ASP.Net Application (Provider)
Now for the application itself - first off you need to locate and download the provided public key (certificate) for the social platform host and either store it on the filesystem or in the case of this demo we'll just store it as a string, like so:
public class OpenSocialCertificates
{
private const string _friendsterCertificate =
@"-----BEGIN CERTIFICATE-----
MIIB2TCCAYOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAvMQswCQYDVQQGEwJVUzEL
MAkGA1UECBMCQ0ExEzARBgNVBAoTCkZyaWVuZHN0ZXIwHhcNMDgwODEzMTgwMzQ5
WhcNMTQwMjAzMTgwMzQ5WjAvMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzAR
BgNVBAoTCkZyaWVuZHN0ZXIwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAyVjnX2Hr
SLTyAuh2f2/OSRWkLFo3+q+l0Czb48v24Me6CsoexkPgwLOjXmPn/Pt8WtwlisQP
tZ9RX30iymg0owIDAQABo4GJMIGGMB0GA1UdDgQWBBQlDiW+HfExpSnvWqM5a1JD
C+IMyTBXBgNVHSMEUDBOgBQlDiW+HfExpSnvWqM5a1JDC+IMyaEzpDEwLzELMAkG
A1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQKEwpGcmllbmRzdGVyggEAMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADQQCXFtEZswNcPcOTT78oeTuslgmu
0shaZB0PAjA3I89OJZBI7SknIwDxj56kNZpEo6Rhf3uilpj44gkJFecSYnG2
-----END CERTIFICATE-----";
public static X509Certificate2 FriendsterCertificate
{
get { return new X509Certificate2(Encoding.ASCII.GetBytes(_friendsterCertificate)); }
}
}
It's worth noting that the certificates can be changed at any time - but fair warning will be given (according to the document) - and that the location (url) of the certificate is actually included as a parameter in the requests the host makes to your application (xoauth_signature_publickey) - so it's fairly trivial to implement a caching scheme to automatically pull down and update the certificate if it has changed.
Now that we have the certificate we just need to validate the request, in this cause I'm just going to check it's been signed - I've left validating timestamps and nonces out of the example, as these tend to be propritary to the app your building, but both are easy to implement.
public partial class SocialService : Page
{
protected void Page_Load(object sender, EventArgs e)
{
ValidateWithDevDefinedOAuth();
// now handle the request...
}
private void ValidateWithDevDefinedOAuth()
{
try
{
OAuthContext context = new OAuthContextBuilder().FromHttpRequest(Request);
var signer = new OAuthContextSigner();
var signingContext = new SigningContext {Algorithm = OpenSocialCertificates.FriendsterCertificate.PublicKey.Key};
if (!signer.ValidateSignature(context, signingContext))
{
throw new OAuthException(context, OAuthProblems.SignatureInvalid, "check certificate is still valid");
}
}
catch (OAuthException authEx)
{
Response.Clear();
Response.Write(authEx.Report.ToString());
Response.End();
}
}
}
The process is basically using the OAuthContextBuilder class to construct a context (which is used to calculate a signature base) from the current pages request. It then constructs a signer (used for signing requests and checking their signatures i.e. validation) and a signing context, which is used to provide additional information to the signer, such as the public key of the friendster certificate.
We then invoke ValidateSignature to ensure the signature is valid - if not we throw an exception.
Finally if an OAuthException is thrown we catch it and render it's report to response stream and close it - this provides diagnostic information as per the OAuth problem reporting extension.
Hope this has been useful to some people out there - BTW I'm no OpenSocial expert, so please direct general OpenSocial questions to the apropriate google groups, I can only help with OAuth library questions.
Problems with Friendster Requests
As a side note - for anyone who's tried writing an OpenSocial application using DevDefined.OAuth to validate request signatures they may have found it didn't work! This was a result of Friendster appending an ampersand (&) to the end of the query string on the Url, which was causing the signature base to be incorrect (I'm not sure if this is an issue for other OpenSocial implementations) - The code now checks for this and removes it if discovered - and signature validation works as expected.
 Tuesday, September 09, 2008
Unfortunately the old ADVANCED-DOTNET mailing list at DevelopMentor is being put down, like an old but still
on the odd occasion faithful dog.
This would be one of the first .Net mailing lists I ever really latched onto (about 6 years ago...) and there have been some pretty bright sparks on their since day one.
Hi all
We are currently undertaking an infrastructure review at DevelopMentor and
have realised that apart from this one list the listserv is not really used
any more. Unfortunately we cannot really justify maintaining the server for
this one list and so we have decided to retire the listserv.
I created this list as a moderated list six and a half years ago and so feel
a bit sad to see its passing, but the world has moved on from mail
reflectors to blogs, web forums and other discussion mediums.
We will be taking the server offline on the 30th September so you have a bit
of time to get anything you need from the archives
Thanks for your involvement over the last few years
Richard Blewett
CTO
DevelopMentor
I think what's more disappointing is that in turning it off they certainly haven't spent much time thinking about an exit plan, because there's no archive availability (the listserv is getting turned off completely) or alternative place identified for list participants to move to... I often think this is something that needs to be thought about up front (and budgeted for, almost in some separate trust fund) especially as communities and social platforms proliferate - it's a shame to see information evaporate.
That said it looks like some of the long time readers of the group are working to migrate the server away from develop mentor, or to move onto this google group - be interesting to see where this goes.
On a side note I wonder how much sites like stack overflow will errode the last remnants of mail-only technical mailing lists... personally (while I've been beta testing it) I've found the stack overflow concept doesn't really gel with me - but I can see it's appeal to others - personally I prefer discussion over problem "resolution" and the ability for a group to collectively choose not to answer a problem (because it's but 2 clicks away on a simple google search) - where as with the reputation system in Stack overflow the simple/dumb/obvious questions are like crack for the reputation kidies.
On the same note, how much will stack overflow and similar concepts errode organic blog discovery (which is normally while someone is trying to find an answer to a question).... hmmm
 Monday, September 08, 2008
You may recall a few months back I released an OAuth library for .Net (which can be found here on google code) - at the time of writing that library the only other OAuth "solution" for .Net developers was a C# file containing some simple helper functions, that didn't even produce valid results in many cases, and the rather basic implementation as part of the restful chess/myspace example. Well the guys at Madgex in the UK have now released their own OAuth.Net library.. for more details you can: As for differences between the two implementations... from a 50K foot glance. - There's a dependency on the Windsor container when using the Madgex library (if you want to use it's out the box implementation / configuration examples etc.)
- The Madgex library includes a http module for making a provider implementation easier when building web apps.
- The madgex library appears to take a harder dependency on HttpRequest then the DevDefined library (but that's just a hunch, saw it in a few interface definitions, rather then some wrapper equivalent).
- The madgex library looks a little more polished (i.e. xml docs) and has a configuration section.
- The Madgex library features some niceities like Sliding window validation support (i.e. they only allow messages to be supplied where the timestamp falls within a certain time window of the server, and keep the list of previous nonces only for the period of that window - flushing nonces that are not longer required via a background thread - saving on the volume of nonces to record i.e. for replay attacks). Of course it's an in-memory solution, so not suited to farms, but still cool.
- Slightly less fluent consumer implementation, I prefer my libraries consumer implementation, but of course that's just me :P
- Both libraries are under the MIT license.
All said and done it's a very sound effort, great work guys! And it's awesome to have some choice emerging in this space.
 Tuesday, September 02, 2008
So I received a question recently via email from someone following the container tutorials, which read like so:
Read through you tutorials and great work!
Have a question for you though, that I can't seem to find an answer in google.
On decorators. How do you provide state dependencies that are unknown at configuration time?
So I ask for an IRepository and I have configuration setup to wrap it in a IValidator
and maybe an ISecurity. However, ISecurity has a dependency on a runtime determined
role (say from multiple sources, possibly including a state value on IWidget) and the user id (for argument sake isn't available on the context).
I want to call T Get() on IRepository.
How do you get it all setup?
Many Thanks!
As I see it there were two distinct questions asked: - How to wire up generic decorator chains (though I suspect they already know how to do that).
- How to pass in parameters/dependencies at run time.
So Let's look at doing these two things, I'm going to steer clear of xml configuration because that's so 2 years ago ;o) First off let's create the repository interface:
public interface IRepository<T>
where T : class, new()
{
T Get(int id);
}
Then the root implementation (we can't keep chaining forever, at some point we have to hit an implementation which can actually return the results we want).
public class StubRepository<T> : IRepository<T>
where T : class, new()
{
public T Get(int id)
{
return new T();
}
}
And finally a decorator for "security"...
public class SecurityDecorator<T> : IRepository<T>
where T : class, new()
{
private readonly IRepository<T> _inner;
public SecurityDecorator(IRepository<T> inner)
{
_inner = inner;
}
public T Get(int id)
{
return _inner.Get(id);
}
}
better have a widget too... for good measure:
At this point we can write a test - I'm an xUnit fanboy these days (typing less == good) so let's take a look:
public class ContainerTests
{
private readonly IWindsorContainer container;
public ContainerTests()
{
container = new WindsorContainer();
container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (SecurityDecorator<>)));
container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (StubRepository<>)));
}
[Fact]
public void GetRepository_ForWidget_ReturnsSecurityDecoratorOfTypeWidget()
{
var widgetRepository = container.Resolve<IRepository<Widget>>();
Assert.True(widgetRepository is SecurityDecorator<Widget>);
}
}
Notice we register the components in top to bottom order i.e. decorators first, followed by the underlying implementation, for something as simple as this you don't really need to use the fluent interface for registering components - but I find it's good to be consistent. Now, the second question is about injecting "context" - this is really just another way of saying "some of my dependencies can't be known until just before I attempt to resolve the service" ... no problem... so let's make some modifications: First off I'm going to make a user...
public interface IUser
{
}
Next thing I'm going to do is add a User property to my security context (ugh, this seems like a better job for some kind of "ICurrentUserHolder" service, but that's beside the point).
public class SecurityDecorator<T> : IRepository<T>
where T : class, new()
{
private readonly IRepository<T> _inner;
public SecurityDecorator(IRepository<T> inner)
{
_inner = inner;
}
public T Get(int id)
{
return _inner.Get(id);
}
public IUser User { get; set; } // <-- the current user
}
Now let's add another test to ensure everything is being injected properly...
public class ContainerTests
{
private readonly IWindsorContainer container;
private readonly IUser user = MockRepository.GenerateStub<IUser>();
public ContainerTests()
{
container = new WindsorContainer();
container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (SecurityDecorator<>)));
container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (StubRepository<>)));
}
[Fact]
public void GetRepository_ForWidget_ReturnsSecurityDecoratorOfTypeWidget()
{
var widgetRepository = container.Resolve<IRepository<Widget>>();
Assert.True(widgetRepository is SecurityDecorator<Widget>);
}
[Fact]
public void GetRepository_ForWidget_WhenSupplyingUserInjectsUserIntoSecurityRepository()
{
var securityDecoratorForWidget = (SecurityDecorator<Widget>) container.Resolve<IRepository<Widget>>(new {User = user});
Assert.Same(user, securityDecoratorForWidget.User);
}
}
Notice the additional argument of an anonymous class being passed to Resolve, this allows us to provide additional parameter dependencies (in this case a stub user is being supplied). Finally what about passing in some roles... this is much of the same, but I'll include it for completeness... so we add a role interface:
public interface IRole
{
bool IsMember(IUser user);
}
Then we'll add a collection of roles to the decorator and provide a rather primitive check against the roles when attempting to get a widget instance:
public class SecurityDecorator<T> : IRepository<T>
where T : class, new()
{
private readonly IRepository<T> _inner;
public SecurityDecorator(IRepository<T> inner)
{
_inner = inner;
}
public T Get(int id)
{
CheckPermission();
return _inner.Get(id);
}
public IUser User { get; set; }
public IList<IRole> Roles { get; set; } // <-- the roles to check
private void CheckPermission()
{
if (User == null || Roles == null) return;
if (Roles.Any(role => !role.IsMember(User)))
{
throw new Exception("You do not have permission");
}
}
}
And finally we update our test with checks for both passing and failing on the permissions check.
public class ContainerTests
{
private readonly IWindsorContainer container;
private readonly IUser user = MockRepository.GenerateStub<IUser>();
private readonly IRole failingRole = MockRepository.GenerateStub<IRole>();
private readonly IRole passingRole = MockRepository.GenerateStub<IRole>();
public ContainerTests()
{
container = new WindsorContainer();
container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (SecurityDecorator<>)));
container.Register(Component.For(typeof (IRepository<>)).ImplementedBy(typeof (StubRepository<>)));
passingRole.Stub(stub => stub.IsMember(user)).Return(true);
}
[Fact]
public void GetRepository_ForWidget_ReturnsSecurityDecoratorOfTypeWidget()
{
var widgetRepository = container.Resolve<IRepository<Widget>>();
Assert.True(widgetRepository is SecurityDecorator<Widget>);
}
[Fact]
public void GetRepository_ForWidget_WhenSupplyingUserInjectsUserIntoSecurityRepository()
{
var securityDecoratorForWidget = (SecurityDecorator<Widget>) container.Resolve<IRepository<Widget>>(new {User = user});
Assert.Same(user, securityDecoratorForWidget.User);
}
[Fact]
public void Get_ForWidgetWhenUserMatchesAllRoles_ReturnsWidget()
{
var securityDecoratorForWidget =
(SecurityDecorator<Widget>) container.Resolve<IRepository<Widget>>(new {User = user, Roles = new List<IRole> {passingRole}});
Assert.NotNull(securityDecoratorForWidget.Get(1));
}
[Fact]
public void Get_ForWidgetWhenUserDoesNotMatchAllRoles_ThrowsException()
{
var securityDecoratorForWidget =
(SecurityDecorator<Widget>) container.Resolve<IRepository<Widget>>(new {User = user, Roles = new List<IRole> {passingRole, failingRole}});
var exception = Assert.Throws<Exception>(() => securityDecoratorForWidget.Get(1));
Assert.Equal("You do not have permission", exception.Message);
}
}
And that's it... could not be simpler.
 Wednesday, August 27, 2008
It's been a back and forth discussion on the OAuth list for a while now - and with some people (zealots? ;o) having ideas they weren't even willing to contribute to the OAuth group until the IPR was sorted I'm glad to finally see it's been completed, this should hopefully help to improve the longevity and adoption of the standard by some who have been fence sitting. So what's happened? Well all all parties involved in building the original spec have signed an agreement of non-assertion, so now OAuth can be safely implemented anywhere without concern about lawsuits related to the IP in the spec. OAuth is a pretty elementary standard in it's version 1 state - so in some ways it was inevitable that this would happen (or at least I thought so) - there wasn't much to gain by any of the contributors blocking the progress of it becoming an open standard - but it's involved a lot of work to get it there by all accounts, so full credit goes to all involved! For a detailed writeup check out the post from Eran Hammer-Lahav or the post on Read/write web. Conspicuous by it's absence is Microsoft, but for no other reason than they did not contribute to the OAuth standard - and so didn't have to sign - but of course LiveId does tackle delegated authentication - so in some ways they have a competing platform for handling delegation, presumably because OAuth doesn't provide a rich enough set of features at this stage to handle some of the more complex scenarios around scalability, signing message bodies etc. - though I'm just hazarding a guess, LiveId was presented at the OAuth summit earlier this year.
 Monday, August 18, 2008
Hi all, there's an Architecture chat this Thursday - 21st August @ 11:30am onwards. Some things that I've caught my eye since last time: - .Net 3.5 SP1 and VS2008 RTM are here
- VS2K8SP1 and SQL2K8 installs are a big mixed bag, some people no problem, other tearing hair out!
- And so are the war stories such as regressions and critical changes - doh!
- Visibility and trouble with non-developers being unable to quantify the quality of developer outputs - sparked off by this post by Casey.
- Resharper 4.01 RC1 is out.
- ASP.NET MVC now and in the future (i.e. where it's going, and perhaps a discussion on future of monorail vs. MVC and Monorail 2??).
- Security practices on MVC, WCF etc.
- Redmine - an interesting (and nicer) alternative to Trac - wonder if there's an easy transition path for existing Trac sites?
Edit: updated this list with some suggestions from others. If anyone has any topic suggestions - just make a post on this entry, or send me an email / IM message. Details of previous posts and directions etc. can be found here on the wiki.
Here's the write-up for Architecture Chat #32 (from Thursday 7 th August 2008) ... some of the things we discussed: - Jabl / Jass (Javascript abstraction language) - we discussed this approach of writing languages that transform into another language - the tradeoffs of debug experience vs. productivity etc.
- Debug experiences in DSL's and in particular the lack of support in these language rewriting/transformation projects.
- The magic bullet language i.e. two-way debugging experience, language independent refactoring support, modular/pluggable language support (sorta like Boo).
- Code camp at the end of this month.
- Self explaining code / blaming code (i.e. code that can explain the decisions it makes in english, or at least identify the blame (i.e. steps) that lead to the result it selected. Though we didn't bring it up, I quite like the way Rhino Security does this.
- xUnit thoughts after a month of using it on a commercial project.
- Ice ZeroC - WCF alternative?
- Sql Server partitioned tables, and the simpler query plans / improvements in 2008.
See the wiki for write up's of previous chats, thanks to all those who attended.
 Friday, August 15, 2008
Yesterday afternoon I presented a quick 20 minute presentation to the Enterprise Architect user group - it was an interesting opportunity to talk with both an Enterprise Architect lead developer and analysts/BA's etc. who are using Enterprise Architect on a daily basis - there's nothing quite like doing something and then even more so presenting on what you've done to really firm up some conclusions / ideas around it (and as is often the case with me, spark 20 ideas for new products I could build to make it better/smarter). For anyone who's interested here's the slide deck I presented - and also some links to things that were discussed: Thanks to catch for hosting the group and providing the video conferencing facilities to link Auckland / Wellington (small tip, if you are presenting to two groups be sure to sit at the end of the table looking towards the camera, or your spend your whole time ping-ponging your head towards one group and the other ;) - and also thanks to everyone who came along and listened. Also of interest was the discussion after the presentation around providing a number of example/sample MDA transformations through Sparx Systems New Zealand site - which should mean that before the end of the year you will be seeing both guidance and examples on developing MDA transformations targeting NHibernate, NHibernate search, ActiveRecord, Monorail and RhinoSecurity starting to emerge (what I tend to loosely call the "Castle stack" for want of a better term.) - which I'll post about it as it starts to happen.
 Wednesday, August 06, 2008
There's a few things going on in Auckland over the next month or so, just to summarize if you haven't been paying attention :) So plenty of things going on! I would suggest signing up for the code camp sooner rather then later if you don't want to miss out - also if you know of any other events that I've left off this list, drop me a comment and I'll add them to it.
 Wednesday, July 23, 2008
So I see more people rewriting my container tutorials lately... First we have the unity tutorials - as covered by Michael McGuire... which I mentioned a while back. Now we have the binsor tutorials which have sprung up lately - from ruprict covering the same concepts, but with Binsor syntax - which is quite handy for those that are boo-inclined! I also believe a set of Ninject tutorials are being written by Simone Chiaretta (codeclimber) in his spare time as well (and who is not jealous of Ninject's website! ;o) It's encouraging to see interest still growing in IoC on the .Net Framework.
 Monday, July 14, 2008
Looks like I've been tagged twice - so here goes. How old were you when you first started programming?Apple II e when I was like 7, Vic20 when I was like 8... but really my start was about 10 with GW-Basic on a 286 AT 16mhz. How did you get started in programming?I was interested in programming from about age 6 or 7.. though I think I was 12 when I taught myselfTurbo C++ (And the object oriented concepts that went with it) - so I've spent over half my life in object oriented languages - not sure if that's good or bad! I owe my parents a large amount of gratitude as they recognized my interests early on, and though we had little money they spent a lot trying to encourage my interests (computers were not so cheap in the 80's). What was your first language?Basic on the Apple II e and Vic20 - but really I think it wasn't until GW-Basic in Dos4 (and later quick basic) that I became fluent at writing programs and starting to break problems out into a series of functions. After basic came C++ (and in-line assembler), Tcl/Tk and Visual Basic 3 or 4 - then once I started tertiary study I added Pascal, Delphi, Jade, bash, java and perl to the list. What was the first real program you wrote?A "real" program ... I'm going to take "real" as something commercial with "users" ... hmm.. I had a part-time job when I was like 14 helping to add functionality to a C based DOS accounting system used around New Zealand - That'd be the first "real" program I added code to. Around 17 I started writing a lot of code for open source projects [same time I started studying at Unitec] (I think all the projects are dead and gone now) and had a keen interest in writing libraries for game development prior to the advent of hardware accelerated 3D, later transferring that interest to OpenGL once Voodoo and NVidia hardware started getting cheaper. What languages have you used since you started programming?Basic (at least 4 or 5 variants), C, C++, Tcl/tk, Bash, Pascal, Jade, Java, JavaScript, Python, Ruby, ASP, T-SQL, Visual Basic 3 and above, VB.Net, F#, VBA, Lisp, Perl, Boo and a few others - though C# has been my language of choice since the early beta's of the .Net Framework v1. What was your first professional programming gig?I think probably working as a Junior at Terabyte Interactive (when they were based in Newmarket) on a rowing machine C++/OpenGl visualization app (the infamous RowPro project). If you knew then what you know now, would you have started programming?Without a doubt - I was passionate about it when I was 8... I'm still passionate about it after 20 years. It scratches 2 itches I've had my entire life, a need to create and a need to debate/discuss/analyze problems/challenges. If there is one thing you learned along the way that you would tell new developers, what would it be? Learn to learn, and if you don't like learning find a new profession. I almost feel like learning is my job, and developing solutions is a side-effect of trying to achieve my primary objective of learning. What's the most fun you've ever had ... programming?Hmm... I couldn't pick any one project - most fun environment-wise would be my early days a Terabyte, it had a wonderful dot-com feel, and we didn't have much work on (at times), so we got to pursue our own pet projects and take long team breakfasts in the local cafe - A fun environment, albeit a doomed one. Probably since then I would say the "Syzmk Rich Media Processor" - an application which had a wonderful variety of requirements and an interesting suite of technologies (it was developed with early releases of the Castle project and betas of the .Net Framework 2.0) and was one of the first projects I approached in a TDD fashion. Who’s next?
 Monday, June 30, 2008
Jonathon Rossi over in Brisbane has been hard at work on the CVSI project (Castle Visual Studio Integration) and has released version 0.3 which now supports VS 2008 - for those not in the know CVSI provides nvelocity intellisense when writing views for monorail. I did some testing of some earlier releases last week and it's looking good, hilights include: - New installer which supports 2005 and 2008.
- Basic XHTML intelisense.
It also includes some fixes which means the intelisense now works when the templates are not in a web application project (useful for those of us writing applications where we have pluggable modules) and fixes for multi-level inheritence, so helpers and view components with multiple levels of base class i.e. FormHelper (which now inherits from AbstractFormRelatedHelper) will be included in the list of classes, something which bugged me with earlier releases on 2005. Great work Jono!
 Thursday, June 19, 2008
If you recall many moons ago I posted a series of articles on the Castle Project's IOC Container "Windsor" teaching the fundamentals of IoC with a practical bent - lots of people liked them, and I still get feedback every now and then from people starting to use windsor and finding them useful. At any rate Michael McGuire was once such person who read those tutorials a year or so ago and has now started a series of his own - mirroring my castle container tutorials but with the P&P Unity container instead - you can find it here. As someone who has not given Unity much more then a brief skim it's a nice way to quickly get up to speed on some of the key differences. So far after reading a couple of articles I've learnt. - You need to implement your own type converters for things like arrays or dictionaries in configuration.
- Configuration syntax is not particularly human-friendly, obviously designed for management via a tool - requiring the entry of full types all over the spot like "Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration" - just to register a component!
- Default lifestyle is transient... hmmm.. personally I think singleton is more-often the norm for me when writing applications, but it really depends on how the container is being used/abused I guess.
- Support for multiple configurations looks a little more baked in - but this is trivial stuff to implement in most containers.
I'll be interested to see how decorator chains etc. are implemented in Unity. Good work Michael.
 Saturday, June 14, 2008
 Version 1.0.0.0 of splicer (the little video/audio composition library that leverages DirectShow which I started a few years ago) is now available on Codeplex here this marks a milestone in stability, and probably the main "feature" of this release is 64bit support, something that's been bugging me for ages as I could only work on the project in a VM! A quick list of changes since the last release are: - Now uses DirectShow.Net 2.0 (thanks to felix, a fellow NZ'r).
- RenderProgress event.
- Renderers are disposable.
- Support for 64bit operating systems.
- Vista fixes/support.
- Additional samples (i.e. SampleTimeWatermarkParticipant, and a few others).
- Tests updated for NUnit 2.4.7.
- Solution upgraded to VS2008.
What's splicer?With this library and a little imagination you can:
- Encode video or audio suitable for use on a website.
- Create slide shows from images, videos and audio.
- Apply effects and transitions to audio and video.
- Grab System.Drawing.Image clips from a video at certain times.
- Modify individual video frames during encoding via standard C# mage Drawing code.
- Add new soundtracks to existing video clips.
- Watermark videos.
- Build a video editing suite, if you were so inclined.
 Wednesday, June 11, 2008
DevDefined.OAuthI have a first release of my OAuth implementation up on google code, you can read a little more about it here and the code can be found here. It's released under the MIT license, basically do what you like with it. The library includes both consumer and a provider implementations - test coverage is pretty poor, as it was originally put together as part of my REST presentation to the local Ellerslie .Net user group a few weeks ago, but as I work through the code and rewrite various sections in my spare time it should become a little more robust.
If you're serious about using this code then I would suggest reviewing the OAuth core spec 1.0 and the OAuth problem reporting extensions. The OAuth wiki and google group are also great places to learn more about OAuth. I have not added the MonoRail examples back to the code yet - but will shortly - and will probably provide a WCF implementation as well. I've also posted a short intro to OAuth - OAuth for beginners - for those who are interested.
 Wednesday, February 20, 2008
So a few weeks back there was a post on the Genome TeamBlog which included a link to one of my lambda abuse posts from last year. At any rate - the problem they faced was that with code like this:
DataContext Context = new DataContext();
string connStr = "";
DataDomainSchema schema = DataDomainSchema.LoadFrom("SomeMappingFile");
schema.CreateDbSchema(connStr);
DataDomain dd = new DataDomain(schema, connStr);
using (Context.Push(ShortRunningTransactionContext.Create()))
{
Customer tt = dd.New<Customer>();
tt.Name = "TechTalk";
RootProject tt_hk = dd.New<RootProject>();
tt_hk.Name = "Housekeeping";
ChildProject tt_hk_hol = dd.New<ChildProject>();
tt_hk_hol.Name = "Holiday";
tt_hk.ChildProjects.Add(tt_hk_hol);
ChildProject tt_hk_ill = dd.New<ChildProject>();
tt_hk_ill.Name = "Illness";
tt_hk.ChildProjects.Add(tt_hk_ill);
tt.RootProjects.Add(tt_hk);
RootProject tt_g = dd.New<RootProject>();
tt_g.Name = "Genome";
ChildProject tt_g_dev = dd.New<ChildProject>();
tt_g_dev.Name = "Development";
tt_g.ChildProjects.Add(tt_g_dev);
ChildProject tt_g_mnt = dd.New<ChildProject>();
tt_g_mnt.Name = "Maintenance";
tt_g.ChildProjects.Add(tt_g_mnt);
tt.RootProjects.Add(tt_g);
Context.CommitCurrent();
}
You ended up with a very flat member initialization structure plagued with: - Having to explicitly name child instances being added to collections - there's a lot of unnecessary noise.
- Where you can't easily see the structure i.e. it's not visually hierarchical, so at a glance you're not sure just what the structure is compared to say looking at an xml document with nested elements where it's quite obvious.
At any rate, the guys at the Genome project attempted to overcome this using the nested lambdas (what I coined a "DSL" at the time, though It's a terrible and inaccurate term for what's effectively just a bit of a "trick" relying on side effects of evaluation) - it didn't go so well though because of course at first glance the syntax look strongly typed, the reality is it's anything but, and refactoring tools just aren't going to do things like renaming of keys in the hash style syntax i.e. key => value, because the key is just a Lambda parameter. But all is not lost - of course with C# 3.0 we already have a great syntax for doing this kind of hierarchical initialization, say for this set of types:
public class BlogPost
{
private readonly List<string> _tags = new List<string>();
private readonly BlogUser _createdBy = new BlogUser();
public string Title { get; set; }
public string Body { get; set; }
public List<string> Tags
{
get { return _tags; }
}
public BlogUser CreatedBy
{
get { return _createdBy; }
}
public BlogUser LastEditedBy { get; set; }
}
public class BlogUser
{
public int Age { get; set; }
public string Name { get; set; }
}
We could do something like this to initialize an instance of BlogPost:
BlogPost post = new BlogPost()
{
Title = "Post on Lambdas",
Body = "This is a post...",
Tags =
{
".Net",
"Lambda",
"C#3.0"
},
CreatedBy =
{
Name = "Jane Doe",
Age = 35
},
LastEditedBy = new BlogUser()
{
Name = "Joe Bloggs",
Age = 25
}
};
But the catch for the Genome guys is that it looks like they need to construct their entities using their DataDomain class ... I don't know about how there product works but I can only assume it's either to get a transparent proxy for change tracking purposes or to enlist it into the current session etc. (though if it's just to enlist the entity I can't see why they need to bother with getting the DataDomain to create a new instance, surely they could manually enlist it). At any rate that's irrelevant :) So I got to thinking that of course member initialization is one of the Lambda-friendly things we can do because it's expressed in a single statement - so we can happily take the above code snippet and express it like so:
BlogPost post = evaluator.Create(() => new BlogPost()
{
Title = "Post on Lambdas",
Body = "This is a post...",
Tags =
{
".Net",
"Lambda",
"C#3.0"
},
CreatedBy =
{
Name = "Jane Doe",
Age = 35
},
LastEditedBy = new BlogUser()
{
Name = "Joe Bloggs",
Age = 25
}
});
Where evaluator is an instance of a class I wrote called ServiceInjectionEvaluator ... the Create method (as you can probably guess) has the following signature:
public T Create<T>(Expression<Func<T>> expression)
The service injection evaluator just relies on being configured with an IServiceProvider capable of resolving instances of types... at this point we just unwind the expression, substituting our own instance activation mechanism wherever we stumble upon a NewExpression and walking through the expressions executing each bit as required - though it makes the assumption that you're going to have either a New or MemberInit expression at the top level of the Lambda, otherwise we just compile the whole thing and throw it back without any changes (because I don't want to bother writing code to visit the other types of expression node).
public class ServiceInjectionEvaluator
{
private readonly IServiceProvider _serviceProvider;
public ServiceInjectionEvaluator(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public T Create<T>(Expression<Func<T>> expression)
{
switch (expression.Body.NodeType)
{
case ExpressionType.New:
case ExpressionType.MemberInit:
return (T)EvaluateExpression(expression.Body);
default:
return expression.Compile().Invoke();
}
}
private object GetInstanceWithInit(MemberInitExpression expression)
{
object instance = GetInstance(expression.NewExpression);
foreach (MemberBinding binding in expression.Bindings)
{
ApplyBinding(instance, binding);
}
return instance;
}
private void ApplyBinding(object instance, MemberBinding binding)
{
switch (binding.BindingType)
{
case MemberBindingType.Assignment:
ApplyAssignmentBinding(instance, (MemberAssignment)binding);
break;
case MemberBindingType.ListBinding:
ApplyListBinding(instance, (MemberListBinding)binding);
break;
case MemberBindingType.MemberBinding:
ApplyMemberBinding(instance, (MemberMemberBinding)binding);
break;
default:
throw new NotImplementedException();
}
}
private void ApplyMemberBinding(object instance, MemberMemberBinding binding)
{
PropertyInfo property = (PropertyInfo)binding.Member;
object memberValue = property.GetValue(instance, null);
foreach (MemberBinding childBinding in binding.Bindings)
{
ApplyBinding(memberValue, childBinding);
}
}
private void ApplyListBinding(object instance, MemberListBinding binding)
{
object list = ((PropertyInfo)binding.Member).GetValue(instance, null);
foreach (ElementInit elementInit in binding.Initializers)
{
Delegate compiled = Expression.Lambda(Expression.NewArrayInit(typeof(object), elementInit.Arguments.ToArray())).Compile();
object[] arguments = (object[])compiled.DynamicInvoke();
elementInit.AddMethod.Invoke(list, arguments);
}
}
private void ApplyAssignmentBinding(object instance, MemberAssignment assignment)
{
object value = EvaluateExpression(assignment.Expression);
PropertyInfo info = (PropertyInfo)assignment.Member;
info.SetValue(instance, value, null);
}
private object EvaluateExpression(Expression expression)
{
switch (expression.NodeType)
{
case ExpressionType.New:
return GetInstance((NewExpression) expression);
case ExpressionType.MemberInit:
return GetInstanceWithInit((MemberInitExpression) expression);
default:
return Expression.Lambda(expression).Compile().DynamicInvoke();
}
}
private object GetInstance(NewExpression expression)
{
return _serviceProvider.GetService(expression.Type);
}
}
The only thing left is to then either provide an existing instance of IServiceProvider (i.e. the Windsor container) or creating an adaptor
public class DataDomainServiceProvider : IServiceProvider
{
private readonly DataDomain _domain;
private static readonly MethodInfo member = typeof(DataDomain).GetMethod("New");
public DataDomainServiceProvider(DataDomain domain)
{
_domain = domain;
}
public object GetService(Type serviceType)
{
return member.MakeGenericMethod(serviceType).Invoke(_domain, null);
}
}
There's a few things the enterprising mind can do with substitutions and member initialization I can think of, especially around IoC - anyone else have some ideas or thoughts on using/abusing them?
 Monday, February 04, 2008
 So the sun has set on day 1 of the Summer Road Trip 2008 in Auckland - The Presentation was done by JB, Chris and Myself this afternoon - it went very well, people enjoyed the content and the mix of integration, server management, database and development topics really meshed together nicely I thought... There was enough to keep everyone interested, regardless of the hat you wear - and plenty of prizes too - well all love swag right?! Big thanks to our MC Jaqcui, who handled the Intro and Outro and let everyone know about the local Ellerslie & Central Auckland user group's - where I'll be sure to run a few sessions later in the year... and of course Darryl for handling some of the finer details like the venue, lunch, and the dinner afterwards - much appreciated. For all those that came along - first off thanks for coming, obviously without participation in these events they'll just dry up and stop happening - and second don't forgot that there is no time like the present to start picking up these technologies and developing applications with and for them - the products are all but ready, so why can't you be (and not only are they great technologies, they're fun too). The next presentation is in Tauranga - and there are still places left, so sign up here - It's going to be on tomorrow (5th of Feb) at 1:00pm I believe. And finally a short plug ;o)  For anyone that found this presentation interesting and would like to discuss the technical details of things like emerging technologies, general software Architecture, Developer Tools, Running software businesses etc. I also organise the local Sylvia Park Architecture Chat - which is a pretty casual meeting of some very smart people in the .Net Community. We normally get together on a fortnightly basis at Garrisons in Sylvia Park and are always keen to have more people/fresh faces to come along and join in our discussions or even just float some development/architecture questions or problems you might have that the group can help solve - keep an eye on my blog, or the dot.net.nz mailing list for announcements of when we'll next be meeting up :) And all are welcome of course!
 Wednesday, January 09, 2008
Update: 22 nd May 2008 - Please if you have any .Net reactor related queries, post them to this google group, rather then emailing me directly, as you're more likely to get a response. Cheers! If you recall in the last Architecture Chat ( #21) Gareth of Slyce Software mentioned the demise of . Net Reactor, a German code obfuscation product that many users swear by.. but over the past 2 or so months it went completely dark as the company ceased responding to any correspondence, or making releases - where as prior they were almost phenomenally fast to get back to queries, and we releasing every couple of weeks. Well I got an interesting email from a .Net Reactor user who has been suffering the same issues, not having a response out the company in the last couple of months but he did advise that releases are starting to flow out the company again, with 3 new versions released in December... so things could be looking up, even if the wall of silence continues. Apparently it got so bad that even some add-on vendors have withdrawn in-prorgess products due to a lack of communication with Eziriz - what I find interesting here is how quickly all the good work you can do building up a community around a product for developers can unwind - and demonstrates how important a visible "heartbeat" for a product is to keeping trust in your project - be it through regular releases, actively participating in forums and mailing lists or at the very least publishing the odd bit of news on your site. Fingers crossed the company starts answering peoples emails again at any rate - it'd be a shame to see a popular product's community turn their back on it just because their worried it's going to dissappear completely. Right, so yes, there is a point to this post - assuming the worst and .Net Reactor is winding down, can anyone else recommend an obfuscation/licensing products in the sub 300 US$ range that works well? Edit:Shortly after posting this I was notified that Apparently everything is good once more in .Net Reactor land with the lead developer having been taken away from development due to other life issues taking over in the later part of last year, but he's back and developing/communicating once more so it should be "business as usual". I look forward to seeing what cool things Eziriz get up to in 2008! Edit (Again):
And shortly after that I also got an email, so everything is definitely fine once more with .Net Reactor:
Dear Mr. Henderson, I am sorry for the problems you had with my product support. Gareth Hayter referred me to your blog. Please be sure, .NET Reactor product development/support is firing on all cylinders again.
Best regards,
Denis Mierzwiak, Chief Technical Officer.
 Tuesday, December 11, 2007
So my last post was a quick look at Volta & WinForms (if you wonder why I was using WinForms rather then web, I just figured it'd be a good place to start, without the complications of what can/can not be translated to javascript) - I haven't really been keeping track of what other people are doing with Volta, but there have been a couple of posts from Microsoft bloggers, including Wes Dyer (on tier splitting a web application) and Drargos Manolescu (on tier splitting a winforms application) - hopefully some of the other members on the Volta team will pick up the gauntlet and start blogging shortly too. This post is going to be very short (if you ignore the code snippets) - we've already seen how classes can be split into two, one being the client proxy the other the service implementation - but what happens if a class is used in the client and server but isn't fixed/pinned to run on a specific Tier via the RunAt attribute... that's the focus of this post. So, in this example - I'm going to add a helper class to my previous example from the last post - which just formats some text all "pretty" like:
public class HelperClass
{
public string PrettyFormat(string text)
{
return string.Format("--> {0} <--", text);
}
}
Now I'll update my service to use pretty formatting:
[RunAt("Server")]
public class SomeService
{
private readonly HelperClass _helper = new HelperClass();
public string WelcomeMessage(string name)
{
return _helper.PrettyFormat(string.Format("Welcome: {0}", name));
}
}
And lastly, I'll add an additional button called "welcomeLocalButton" which when clicked will make use of the helper to format some text on the client, instead of calling the WelcomeMessage method on the service.
public partial class Form1 : Form
{
SomeService service = new SomeService();
private HelperClass helper = new HelperClass();
public Form1()
{
InitializeComponent();
}
private void welcomeButton_Click(object sender, EventArgs e)
{
welcomeOutput.AppendText(service.WelcomeMessage(nameTextBox.Text));
}
private void welcomeLocalButton_Click(object sender, EventArgs e)
{
welcomeOutput.AppendText(helper.PrettyFormat("Welcome Local " + nameTextBox.Text));
}
}
So this is how the app looks now...  Compile and run - everything works as expected, now looking at the generated client and server assemblies we see both contain... the same class - yep that's right it just duplicates the class in both the client and server tiers, without changing it at all. Now for windows forms this doesn't appear as all that much of a miracle (it's still nice, we wouldn't want helper classes being turned into implicit services just because they're used across tiers)... but for web or other target platforms (such as embedded devices) this is where the elegance begins to kick in, not only are you able to declaratively specify where code is executing, but if you don't specify/fix (I wonder what the correct terminology is here?) a type to a specific tier you get the best of both worlds i.e. code that's native assemblies on the origin/server side and javascript implementations on the client side. So to demonstrate the web equivalent I whipped up the following example - I was trying to think of something interesting that would be useful to do client and server-side - and thought, perhaps I would use Andrew's Inflector.Net - sadly there are a few issues with that, namely Regex isn't supported out of the box in Volta (which is a real shame, this is something I would've have expected to have been in the preview - regex being such a swiss army knife, especially for scripting) - so instead I picked something a little simpler - the Ordinalize functionality from Inflector, and just stripped out the other unrequired methods which would give us grief. So the example is pretty simple, we have a web page that looks like this:  You enter a number, it get's ordinalized, either via a remote call or a client-side call... so let's take a quick look at the code, first we have the ordinalize method:
public static class Inflector
{
public static string Ordinalize(string number)
{
int n = int.Parse(number);
int nMod100 = n % 100;
if (nMod100 >= 11 && nMod100 <= 13)
{
return number + "th";
}
switch (n % 10)
{
case 1:
return number + "st";
case 2:
return number + "nd";
case 3:
return number + "rd";
default:
return number + "th";
}
}
}
Then we have the server-side OrdinalizerService:
[RunAtOrigin]
public class OrdinalizerService
{
public string Ordinalize(string number)
{
return Inflector.Ordinalize(number);
}
[Async]
public extern void Ordinalize(string number, Callback<string> callback);
}
And finally we have the UI code:
public partial class VoltaPage1 : Page
{
Input numberElement;
Button button1;
Div resultsElement;
Button button2;
public VoltaPage1()
{
InitializeComponent();
var ordinalizer = new OrdinalizerService();
button1.Click += delegate
{
var name = numberElement.Value;
resultsElement.InnerText = Inflector.Ordinalize(numberElement.Value);
};
button2.Click += delegate
{
var name = numberElement.Value;
ordinalizer.Ordinalize(
name,
message => { resultsElement.InnerText = "Remote: " + message; });
};
}
partial void InitializeComponent()
{
numberElement = Document.GetById<Input>("Text1");
resultsElement = Document.GetById<Div>("Results");
button1 = Document.GetById<Button>("Button1");
button2 = Document.GetById<Button>("Button2");
}
}
So... what's left after the tier-split? Well if you open up reflector and look at either the client or the server assembly - you will still see the same Inflector class i.e. just like the previous winforms example it just copies it to both tiers - and that's it... no magic at this point, because the process of transforming the class to javascript doesn't occur untill runtime. Though obviously it does need to copy it because the client and service layer are entirely independent. I could stop there - but I'm sure many people are curious as to just what the javascript looks like :) So just to round this post out - we'll take a brief look at the generated javascript - so if you use a tool like firebug while loading a page developed with volta you will see alot of activity going on as individual types are loaded one by one from the server, like so...  There are pages and pages of these calls... though there are plans to reduce the number of round trips in the future (obviously a round trip per type is a pretty bad idea in a complex app) but you need to keep your eye on the prize... Volta is not competing with meticulously hand crafted MVC web-based solutions with little sprinkles of Ajax here and there... the benefits would come from employing it where the complexity and drudgery of client side scripting is overwhelming and large amounts of asynchronous messages are being exchanged between client and server... at least that's where I see a sweet spot... obviously there are plenty of other side-effects as well (ubiquitous refactoring springs to mind). Now if you scroll down past all the standard (BCL) and volta related types you eventually find... no mention of the Inflector type. No magic here though - just type a value into the textbox and click Ordinalize Local - and flick back to Firebug's console... and you will see a request being made for the Inflector type - types are lazy loaded - makes a lot of sense, when you might have types only required by a single UI element on the screen that the user never touches. So here's the request for the inflector type:  Notice the two query string parameters a (assembly) and t (type) ... and now if we were to flick over to the response tab, we would see the javascript produced for that type (see below) Notice it adds this type to the list of types in the assembly, maintaining the same symantecs between javascript and the .net framework - obviously the javascript is a little scary, especially considering all the existing variable names have been lost - but for all that it's quite readable:
var CurrentAssembly = Assemblies["VoltaWeb.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"];
CurrentAssembly.TypeDefs["VoltaWeb.Inflector"] = (function(){
var Ret = {};
var Assembly = CurrentAssembly;
var asmRef_0 = Assembly.References.ref_0();
var typDef_0 = GetTypeDef(asmRef_0, "System.Object");
var typDef_1 = GetTypeDef(asmRef_0, "System.Object");
var typRef_0 = GetTypeRef(asmRef_0, "System.String");
var typRef_1 = GetTypeRef(Assembly, "VoltaWeb.Inflector");
var typRef_2 = GetTypeRef(asmRef_0, "System.Object");
var typRef_3 = GetTypeRef(asmRef_0, "System.Object");
var typRef_4 = GetTypeRef(asmRef_0, "System.Boolean");
var typRef_5 = GetTypeRef(asmRef_0, "System.Int32");
var typRef_6 = GetTypeRef(asmRef_0, "System.Void");
var methDef_0 = GetMethodDef(typDef_0, "ToString", [typRef_0]);
var methDef_1 = GetMethodDef(typDef_1, "Equals", [typRef_2, typRef_4]);
var methDef_2 = GetMethodDef(typDef_1, "GetHashCode", [typRef_5]);
var methDef_3 = GetMethodDef(typDef_0, "Finalize", [typRef_6]);
var methRef_0 = GetMethodRef(typRef_3, "ToString", [typRef_0]);
var methRef_1 = GetMethodRef(typRef_3, "Equals", [typRef_2, typRef_4]);
var methRef_2 = GetMethodRef(typRef_3, "GetHashCode", [typRef_5]);
var methRef_3 = GetMethodRef(typRef_3, "Finalize", [typRef_6]);
var Methods = {}; Methods["meth_13"/*VoltaWeb.Inflector.Ordinalize*/] = function _VoltaWeb_Inflector_Ordinalize_System_String_(param_2) {
var asmRef_0 = Assembly.References.ref_0();
var typDef_0 = GetTypeDef(asmRef_0, "System.Int32");
var typDef_1 = GetTypeDef(asmRef_0, "System.String");
var typRef_0 = GetTypeRef(asmRef_0, "System.String");
var typRef_1 = GetTypeRef(asmRef_0, "System.Int32");
var methDef_0 = GetMethodDef(typDef_0, "Parse", [typRef_0, typRef_1]);
var methDef_1 = GetMethodDef(typDef_1, "Concat", [typRef_0, typRef_0, typRef_0]);
var loc_3 = typDef_0.Initializer({});
var loc_4 = typDef_0.Initializer({});
var loc_5 = typDef_0.Initializer({});
var $next;
$next = 0;
while (true) switch($next) {
case 0:
{
loc_3 = methDef_0(param_2)/*System.Int32.Parse(System.String)*/;
loc_4 = loc_3 % 100;
var br1 = loc_4 < 11;
if (br1 || br1 === "") {
$next = 40;
continue;
}
var br2 = loc_4 > 13;
if (br2 || br2 === "") {
$next = 40;
continue;
}
return methDef_1(param_2, "th")/*System.String.Concat(System.String,System.String)*/;
$next = 40;
}
case 40:
{
loc_5 = loc_3 % 10;
switch(loc_5 - 1){
case 0:
$next = 70;
continue;
case 1:
$next = 82;
continue;
case 2:
$next = 94;
continue;
}
$next = 106;
continue;
$next = 70;
}
case 70:
{
return methDef_1(param_2, "st")/*System.String.Concat(System.String,System.String)*/;
$next = 82;
}
case 82:
{
return methDef_1(param_2, "nd")/*System.String.Concat(System.String,System.String)*/;
$next = 94;
}
case 94:
{
return methDef_1(param_2, "rd")/*System.String.Concat(System.String,System.String)*/;
$next = 106;
}
case 106:
{
return methDef_1(param_2, "th")/*System.String.Concat(System.String,System.String)*/;
}
}
};
Ret["Methods"] = Methods;
var VTable = {};VTable[methRef_0] = methDef_0;VTable[methRef_1] = methDef_1;VTable[methRef_2] = methDef_2
;VTable[methRef_3] = methDef_3;
Ret["VTable"] = VTable;
var Parents = {};Parents[typRef_1.Id] = true;Parents[typRef_2.Id] = true;
Ret["Parents"] = Parents;
Ret["PublicMethods"] = {};
Ret["PublicMethods"]["Ordinalize"] = {};
Ret["PublicMethods"]["Ordinalize"][GetSignature([typRef_0, typRef_0])] = "meth_13"/*VoltaWeb.Inflector
.Ordinalize*/;
Ret["Assembly"] = CurrentAssembly;
Ret["Name"] = "VoltaWeb.Inflector";
Ret["Initializer"] = (function(instance){
return instance;
});
Ret["TypeInitializer"] = (function(_vT){
});
return Ret;
})();
Now the above output was generated because I had enabled "verbose javascript output" - by default this isn't on, but can be enabled via a check box on the Volta tab, in the properties for the Volta project:  For those people who care about their javascript being compacted, this is what the non-verbose equivalent looked like, which has no comments or unnecessary whitespace - though with all the qualified type name strings sprinkled everywhere I think the javascript's always going to be a little weighty, and I do wonder if perhaps they couldn't eliminate the need for a lot of them in the non-verbose javascript via some variables being introduced at the top - just look how many times the "System.String" literal is sprinkled around in this small class.
var CurrentAssembly = Assemblies["VoltaPrelude, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"];CurrentAssembly.TypeDefs["Microsoft.LiveLabs.Volta.JavaScript.Global"] = (function(){
var Ret = {};var Assembly = CurrentAssembly;var oA = Assembly.References.cA();var kA = GetTypeDef(oA, "System.Object");var kB = GetTypeDef(oA, "System.Object");var lA = GetTypeRef(oA, "System.String");var lB = GetTypeRef(Assembly, "Microsoft.LiveLabs.Volta.JavaScript.Object");var lC = GetTypeRef(TypeParameters, "T");var lD = GetTypeRef(oA, "System.Double");var lE = GetTypeRef(oA, "System.Boolean");var lF = GetTypeRef(oA, "System.Int32");var lG = GetTypeRef(Assembly, "Microsoft.LiveLabs.Volta.JavaScript.Function");var lH = GetTypeRef(Assembly, "Microsoft.LiveLabs.Volta.JavaScript.Arguments");var lI = GetTypeRef(Assembly, "Microsoft.LiveLabs.Volta.JavaScript.Global");var lJ = GetTypeRef(oA, "System.Object");var lK = GetTypeRef(oA, "System.Object");var lL = GetTypeRef(oA, "System.Void");var mA = GetMethodDef(kA, "ToString", [lA]);var mB = GetMethodDef(kB, "Equals", [lJ, lE]);var mC = GetMethodDef(kB, "GetHashCode", [lF]);var mD = GetMethodDef(kA, "Finalize", [lL]);var nA = GetMethodRef(lK, "ToString", [lA]);var nB = GetMethodRef(lK, "Equals", [lJ, lE]);var nC = GetMethodRef(lK, "GetHashCode", [lF]);var nD = GetMethodRef(lK, "Finalize", [lL]);var Methods = {};Methods["eEI"] = function(iDV){
var rv = decodeURI(iDV);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.String");}return rv;};Methods["eEJ"] = function(iDW){
var rv = decodeURIComponent(iDW);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.String");}return rv;};Methods["eEK"] = function(iDX){
var rv = encodeURI(iDX);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.String");}return rv;};Methods["eEL"] = function(iDY){
var rv = encodeURIComponent(iDY);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.String");}return rv;};Methods["eEM"] = function(iDZ){
var rv = escape(iDZ);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.String");}return rv;};Methods["eEN"] = function(iD0){
var rv = (function(code){
eval("var temp = " + code);return temp;})(iD0);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly, "Microsoft.LiveLabs.Volta.JavaScript.Object");}return rv;};Methods["eEO"] = (function(dB){
return function(iD1){
var rv = (function(code){
eval("var temp = " + code);return temp;})(iD1);if (rv != null && rv._vT == null) {
rv._vT = dB;}return rv;};});Methods["eEP"] = function(){
var rv = Infinity;if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.Double");}return rv;};Methods["eEQ"] = function(iD2){
var rv = isFinite(iD2);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.Boolean");}return rv;};Methods["eER"] = function(iD3){
var rv = isNaN(iD3);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.Boolean");}return rv;};Methods["eES"] = function(){
var rv = NaN;if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.Double");}return rv;};Methods["eET"] = function(iD4){
var rv = parseFloat(iD4);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.Double");}return rv;};Methods["eEU"] = function(iD5){
var rv = parseInt(iD5);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.Double");}return rv;};Methods["eEV"] = function(iD6, iD7){
var rv = parseInt(iD6, iD7);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.Double");}return rv;};Methods["eEW"] = function(iD8){
var rv = (function(item){
return typeof item;})(iD8);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.String");}return rv;};Methods["eEX"] = function(iD9, iEA){
var rv = (function(item, typeConstructor){
return item instanceof typeConstructor;})(iD9, iEA);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.Boolean");}return rv;};Methods["eEY"] = function(iEB, iEC){
var gE;var $next;$next = 0;while (true) switch($next){case 0:
{
gE = GetTypeDef(Assembly, "Microsoft.LiveLabs.Volta.JavaScript.Function").Methods.eED(iEC);var br1 = gE;if (br1 || br1 === "") {
$next = 12;continue; }return 0;$next = 12;}case 12:
{
return Methods.eEX(iEB, gE);}}};Methods["eEZ"] = function(){
var rv = undefined;if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly, "Microsoft.LiveLabs.Volta.JavaScript.Object");}return rv;};Methods["eE0"] = function(iED){
var rv = unescape(iED);if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly.References.cA(), "System.String");}return rv;};Methods["eE1"] = function(){
var rv = arguments;if (rv != null && rv._vT == null) {
rv._vT = GetTypeDef(Assembly, "Microsoft.LiveLabs.Volta.JavaScript.Arguments");}return rv;};Ret["Methods"] = Methods;var VTable = {};VTable[nA] = mA;VTable[nB] = mB;VTable[nC] = mC;VTable[nD] = mD;Ret["VTable"] = VTable;var Parents = {};Parents[lI.Id] = true;Parents[lJ.Id] = true;Ret["Parents"] = Parents;Ret["PublicMethods"] = {};Ret["PublicMethods"]["DecodeURI"] = {};Ret["PublicMethods"]["DecodeURI"][GetSignature([lA, lA])] = "eEI";Ret["PublicMethods"]["DecodeURIComponent"] = {};Ret["PublicMethods"]["DecodeURIComponent"][GetSignature([lA, lA])] = "eEJ";Ret["PublicMethods"]["EncodeURI"] = {};Ret["PublicMethods"]["EncodeURI"][GetSignature([lA, lA])] = "eEK";Ret["PublicMethods"]["EncodeURIComponent"] = {};Ret["PublicMethods"]["EncodeURIComponent"][GetSignature([lA, lA])] = "eEL";Ret["PublicMethods"]["Escape"] = {};Ret["PublicMethods"]["Escape"][GetSignature([lA, lA])] = "eEM";Ret["PublicMethods"]["Eval"] = {};Ret["PublicMethods"]["Eval"][GetSignature([lA, lB])] = "eEN";Ret["PublicMethods"]["Eval"][GetSignature([lA, lC])] = "eEO";Ret["PublicMethods"]["get_Infinity"] = {};Ret["PublicMethods"]["get_Infinity"][GetSignature([lD])] = "eEP";Ret["PublicMethods"]["IsFinite"] = {};Ret["PublicMethods"]["IsFinite"][GetSignature([lD, lE])] = "eEQ";Ret["PublicMethods"]["IsNaN"] = {};Ret["PublicMethods"]["IsNaN"][GetSignature([lD, lE])] = "eER";Ret["PublicMethods"]["get_NaN"] = {};Ret["PublicMethods"]["get_NaN"][GetSignature([lD])] = "eES";Ret["PublicMethods"]["ParseFloat"] = {};Ret["PublicMethods"]["ParseFloat"][GetSignature([lA, lD])] = "eET";Ret["PublicMethods"]["ParseInt"] = {};Ret["PublicMethods"]["ParseInt"][GetSignature([lA, lD])] = "eEU";Ret["PublicMethods"]["ParseInt"][GetSignature([lA, lF, lD])] = "eEV";Ret["PublicMethods"]["TypeOf"] = {};Ret["PublicMethods"]["TypeOf"][GetSignature([lB, lA])] = "eEW";Ret["PublicMethods"]["InstanceOf"] = {};Ret["PublicMethods"]["InstanceOf"][GetSignature([lB, lG, lE])] = "eEX";Ret["PublicMethods"]["InstanceOf"][GetSignature([lB, lA, lE])] = "eEY";Ret["PublicMethods"]["get_Undefined"] = {};Ret["PublicMethods"]["get_Undefined"][GetSignature([lB])] = "eEZ";Ret["PublicMethods"]["Unescape"] = {};Ret["PublicMethods"]["Unescape"][GetSignature([lA, lA])] = "eE0";Ret["PublicMethods"]["get_Arguments"] = {};Ret["PublicMethods"]["get_Arguments"][GetSignature([lH])] = "eE1";Ret["Assembly"] = CurrentAssembly;Ret["Name"] = "Microsoft.LiveLabs.Volta.JavaScript.Global";Ret["Initializer"] = (function(instance){
return instance;});Ret["TypeInitializer"] = (function(_vT){
});return Ret;})();
At any rate I'm going to wrap it up there for now... work to do, but I have to say for a very early preview Volta is proving suprisingly robust - I really hope in the long term it becomes a product in and of itself, rather then being reabsorbed - to me it's a logical approach to reducing complexity in a lot of what we do today - especially when it comes to embracing the DRY principal.
As mentioned on both Darryl's and JB's blogs - in February of next year Chris, Darryl & JB will be touring around New Zealand to tell you all about "2008" (SQL 2K8, VS.NET 2K8 & Windows 2K8 that is) and they're getting "locals" to participate in the various centers, and I just happen to be that "Local" for Auckland, though hopefully not too " Local". So either follow the links above for the full announcement of centers and dates, or if you are local to Auckland then just click on the following link and sign yourself up for the session on Monday February 4th - it's also worth noting that if you both register and turn up (I believe you have to do both ;o) you go into the draw for one of 3 home servers... education and swag. It should be a lot of fun, so register and come along next year! Edit: just noticed Chris has also posted, and included some extra details - so take a look!
 Sunday, December 02, 2007
So a quick observation on the alt.net conference list: "You’ll be happy to know then that in the new WPF Composite work
we are doing, the DI/IOC mechanism will be decoupled and pluggable. Actually
the next version of Entlib will be the same. There’s a new Dependency Injection
block that will allow you to plug-in the container of your choice."
Which was posted on the alt.net conference yahoo list by by Glen Block from Microsoft. I think this is very good news, at least for the WPF composite work they're doing - it might make it a great deal more appealing to me then the CAB was (I was never a big fan of the CAB because it didn't integrate well with the other stacks of technologies that made me productive). I'm fairly ambivalent about the Enterprise Libraries upcoming pluggable IoC support however - surely the overlap between it and the facilities and services already provided by the IoC container you'd be plugging into would be great ... and IoC is only part of that story... for a number of common services (i.e. logging, transactions etc.) you're going to have create appropriate wrappers and sandwich things into the containers "abstracted" view of the world, or face tightly coupling your application to the Enterprise Library, I'm not sure there is much of a value proposition there... though I'm open to being educated if any P&P Microsoft people happen to read this. Interestingly enough Jan Van Ryswyck has picked up on this slip from Glen and noted that it also implies Microsoft are writing yet another IoC container that will probably ship with EntLib & the WPF composite work (in whatever shape it eventually takes) and they ask the question " why oh why!" . Personally I think it makes good sense to provide an out of the box IoC container, with it the product is far more accessible to new developers and people reviewing the technology - especially when you consider that: - If support was added into say the Castle Windsor container, it wouldn't see an official release until RC4 was made public - and until then would be in a state of flux as part of the castle trunk.
- People would expect Microsoft to "suggest" an OSS container that works best with their offering - and playing favorites with the .Net OSS community could only do harm to the ecology I feel.
- Microsoft retain consistency with their existing approach of providing an entire stack of technologies for you to get the job done, if that's what your like/want or are told you want.
- They can provide a set of consistent tutorials and training materials for developers to "get up to speed" with for the product, without having to provide umpteen alternative examples for different containers, or explain why the container terminology is slightly different to the product terminology.
So in short, I think it's a positive sign, not a negative one, even if another container is introduced into the mix - I'll be interested in seeing just how they do it (both the container, and the extension points to allow for plugging in a different container)... Though it could just be a hack using IServiceProvider, I wonder if perhaps they may need to go a bit further, so they can register services into the plugged in container with the appropriate lifestyle and configuration etc. Edit: I just noticed Ayende posted about this as well... he seems pretty well aligned with the "why oh why" viewpoint, perhaps I'm missing something - but I just don't see it being all that practical in some scenarios to provide a product that wont work without the developer going through a separate selection process to pick an IoC container, if they don't already use one from the OSS community.
 Wednesday, November 28, 2007

I’ve seen a few posts flying round between Ivan ( 1, 2) and Ayende ( 1) re: meta programming in C# v.next and the implications of it being a statically typed / pre-compiled language... It’s an interesting thought, but I can’t help wondering if implementation of a rich meta-programming environment in C# - allowing changes at both a class and instance level at run-time - wouldn’t go against the original spirit of the language itself, for me at least I’d be looking for a different language if I yearned for meta programming on a daily basis... one that was built from the ground up with my desires in mind. Take a moment to consider if C# had been built with meta-programming in mind from the outset, would we have bothered with declarative attributes?... ruby seems to get on fine without them (well at least until you try to integrate ruby with Java or .Net libraries)... and what about interfaces, what’s the point of them? Language spirit is an interesting thing – I don’t think it’s something intangible (this is science after all), but often it’s something that’s difficult to put into words, because it’s a feeling coming up from a rapid and subconscious judgement call as you work with a language (ah la Blink) – it’s also something that’s difficult to appreciate until you start sitting down and thinking about writing a programming language of your own (what you haven’t? For shame!)... and it builds an immediate appreciation for languages like C# and ruby and there founders – there are lot of difficult decisions, compromises and reasonable defaults that need to be decided on – and a massive amount of jiggling to make sure it all fits well together – so that you can finally identify the essence of the language – and worst of all you’re not just having to satisfy your internal subconscious judgement calls, but a large audience in the development community, so that your language will be adopted by people because it feels "right" to them. I still gravitate towards programming language pragmatics as a good book for examining the spirit of languages throughout the years and guises – it's definitely a book computer science student’s should all be armed with on their first year, though I doubt many will be interested in the nuances of Fortran today. Now, following up on that – I’d like to contrast meta programming with functional programming... are we in need of meta programming as we move towards a more functional approach by necessity (to reduce the overall complexity of software, and take better advantage of existing/emerging hardware by working at a higher level of abstraction, allowing for judgment to be made on our behalf i.e. about parallelization) and what makes more sense for a language like C#? Personally I see C# moving more and more towards providing a pleasant bridge language between the imperative world and the purely functional word (weighed in favour of the imperative world, where as F# is weighed in favour of the functional world) ... and as such it makes more sense to me at least to draw inspiration from that domain, then dynamic languages and meta programming... just my opinion of course. Given the time frames between C# versions – IronRuby should be mature enough by the time c# v.net arrives that it should be a moot concern, and IronPython is already pretty capable in the meta programming stakes as well, if you can hack the whitespace sensitivity. Funnily enough (and this a bold claim I know :) – but I think the pattern matching support and associated features in F# would prove far more valuable tools for solving many of my day to day problems in C# than meta programming would be, when I take a subjective look at the code I write and the goals it’s generally trying to achieve combined with the existing features and practices I’ve already embraced in C# (IoC/DI) it looks to "click" together in a much more cohesive manor. Thoughts?
 Monday, November 12, 2007
So first off... for those who don't know SharePoint... CAML is a bit of swiss army knife... if you understand it, can stand it, and know where to stick it you can pull off some interesting and useful results with SharePoint... I'm no expert however, having only touched it for querying and tweaking it here and there for some custom views. Though I think I can confidently say CAML is a wonderful example of XML Abuse :) At any rate, one aspect of CAML is being able to write CAML queries to query data sources i.e. SharePoint Lists.... I'm against constructing strings for querying data sources, because they're ugly - and difficult to mutate with code, so I decided to give CAML.Net a try (and ended up using it, albeit reluctantly) - here's an example query in CAML:
<Where>
<Or>
<Eq>
<FieldRef Name="ContentType" />
<Value Type="Text">My Content Type</Value>
</Eq>
<IsNull>
<FieldRef Name="Description" />
</IsNull>
</Or>
</Where>
And then in CAML.Net - at first glance it looks ok:
Console.WriteLine(CAML.Where(
CAML.Or(
CAML.Eq(
CAML.FieldRef("ContentType"),
CAML.Value("My Content Type")),
CAML.IsNull(
CAML.FieldRef("Description")))));
But of course then you look a little closer and see that CAML.Where, CAML.Or, CAML.Eq etc. all return strings... so your not actually building a model of your query - which to me immediately removes a large part of the value for this solution. Looking around the blog-sphere I see lots of people using CAML.Net, and yet nobody seems to have a problem with the way it works?... it puzzles me... At any rate.. let's dive into why I don't like this approach... with another example:
Console.WriteLine(CAML.Where(
CAML.Or(
CAML.Eq(
CAML.FieldRef("Title"),
CAML.Value("My Title")),
CAML.Or(
CAML.Eq(
CAML.FieldRef("ContentType"),
CAML.Value("My Content Type")),
CAML.IsNull(
CAML.FieldRef("Description"))))));
And here's the CAML for that:
<Where>
<Or>
<Eq>
<FieldRef Name="Title" />
<Value Type="Text">My Title</Value>
</Eq>
<Or>
<Eq>
<FieldRef Name="ContentType" />
<Value Type="Text">My Content Type</Value>
</Eq>
<IsNull>
<FieldRef Name="Description" />
</IsNull>
</Or>
</Or>
</Where>
Notice the Or inside an Or... this is direct feedback from the CAML query language itself - notably that you can't construct a query with multiple root-level criteria, so your left to construct a tree of Or and And's as required to represent your query - which is ugly, and ultimately confusing - it doesn't express intent well... So my first problem with the CAML.Net approach is it makes me aware of the problems in CAML, when they could've been abstracted away for me... now let's look at a reasonably dynamic CAML query.
string title = "My Title";
string contentType = "My Content Type";
List<string> orFragments = new List<string>();
if (!string.IsNullOrEmpty(title))
{
orFragments.Add(CAML.Eq(
CAML.FieldRef("Title"),
CAML.Value(title)));
}
if (!string.IsNullOrEmpty(contentType))
{
orFragments.Add(CAML.Eq(
CAML.FieldRef("ContentType"),
CAML.Value(contentType)));
}
orFragments.Add(CAML.IsNull(CAML.FieldRef("Description")));
string query = CAML.Where(
OrCamlRange(orFragments.ToArray()));
And suddenly I'm forced into a world of pain - having to manage the various criteria myself, and strings no less - in this case I'm only using Or's - so I can use a little function to stitch everything into a valid query:
private static string OrCamlRange(string[] items)
{
if ((items == null) || (items.Length < 1)) throw new ArgumentNullException("items");
if (items.Length == 1) return items[0];
string[] remainingItems = new string[items.Length - 1];
Array.Copy(items, 1, remainingItems, 0, remainingItems.Length);
return CAML.Or(items[0], OrCamlRange(remainingItems));
}
But I can't help feeling that an opportunity for CAML.Net to really shine has been tarnished by an initial design choice of returning strings, instead of models. At least for my use cases, I would've been much happier with something that returned a model which I could post-parse - to smarten up the experience so I could identify misspelled fields, mutate the query based on user choices etc. Finally, just to be clear - this is not a dig at John Holliday - CAML.Net's author, he's a smart guy who knows a lot more then I ever will about SharePoint! It's merely an opinion/observation on the negatives of query building approaches which don't embrace an intermediate model which can be parsed or mutated.
 Sunday, November 11, 2007
 So I rediscovered my Vietnamese coffee dripper today... and a small cache of Trung Nguyên coffee I had secreted away after getting back from my Asian excursion a while ago... a little dubious as to whether it would have stood the test of time I brewed a test batch... And had completely forgotten just how strong it is... yikes - I've been on caffeine buzz for the last hour or so ... it has such a distinctive flavor too... took me straight back to sitting in 35 degree heat, drinking extremely strong coffee mixed with ice cubes and condensed milk in the Vietnamese jungle... (it was a lot more fun then it sounds, though the sweetened condensed milk is a bit too sweet for my liking) So at any rate - I'm starting to unwind after an incredibly busy period of work - think 16+ hour days for a couple of months ... which has left me a little shattered to say the least... so I'm unwinding a little today... The lawns are mowed, the sun is shining and I've started to read Beautiful Code - which I've heard mixed reviews of, but I figure it'd be a nice change from SharePoint blogs and should hopefully put me in the right frame of mind as a shift my focus back to projects revolving around ALT.Net technologies once again.
 Saturday, November 10, 2007
Here are some more SharePoint hacks (continuing on from my last post here) First off some hacks for the SPGridView which is actually a pretty useful control, but fails to do a few things, like displaying attachment columns as-per SharePoint's default List views (with a little paper-clip symbol), and the second (and much more annoying) it doesn't use the current users regional settings / timezone for formatting DateTime values. The hacks: And finally support for a ListForm replacement web part - after trying to customize the ListForm to suit a customers requirements by creating a CustomListForm in SharePoint designer I gave up in disgust because it's just too limited in what it lets you achieve, and worst of all, it breaks attachments support! So I wrote a small web part to replace it, which allows for fine-grained control of visibility and editability (if that's even a word) of each field, and as an added bonus it doesn't break the attachments functionality. I also wanted to add additional links/buttons to the form which triggered a save including validation etc. - so I did a little hack to implement that as well. I might have a few more to post before the end of the project - but it's almost wrapped up, so these may be the last for a while. Hopefully someone out there finds them useful.
 Wednesday, November 07, 2007
I've been working with SharePoint lately, it's a technology of highs and lows... the highs are when you've finally got something to work that should've worked in the first place, the lows are well... all the times in between. Ok, so that sounds cynical - SharePoint is actually quite a cool product - there's a lot of good in there... stuff that would take you a while to write yourself... but it just tends to drive you a bit crazy, things that look easy from a distance become hard to achieve because of poor documentation, lack of extension points and the difficulty in building testable code. At any rate, while on this project I've been compiling a list of hacks that other people may find useful, which I used to solve a few of the problems I was hitting while developing... here are the first few: There are some more coming shortly.
 Tuesday, October 30, 2007
Hi All! The next Architecture chat is on thursday this week, 11:30am at the Sylvia Park in Auckland ( at Garrisons). As
always, bring along your thoughts and discussions, and in the mean time here are some possible topics for discussion that have caught my eye over the last two weeks.
- Java & .Net
- The IKVM project (Java VM implemented in .Net)
- Accropolis changes
- No new previews
- P&P will provide WPF Composite Client guidance (uh oh)
- Open source CMS's
- F# - becoming a first class language in VS.Net
- PLinq, now GridLinq.
- Recruiting .Net developers how to/approaches.
And if anyone else has suggestions, feel free to throw me a comment/email etc. and hopefully we can get a few more of the regulars back this week. See you all thursday!
Just a quick note that I've put together a small guide on working with the Castle / Nhibernate / RhinoTools trunk here on my wiki, which goes well as a companion to this article on working with the Castle trunk which can be found on using.castleproject.org. Hopefully it proves useful to someone other that myself.
 Tuesday, October 02, 2007
Ok so I must've been sleeping under a rock or something, so this is no doubt old news to many people - but PostSharp completely slipped by without me noticing it until now... Having played with it tonight, I'm definitely liking it :) So far I've just used it for doing some AOP... unlike doing AOP using something like Dynamic Proxy / AspectSharp in Castle, PostSharp gives you a more... personal experience... letting you apply AOP to internal or sealed types, and allowing you to declaratively setup aspects with very little effort... as an example I created a simple little class for recording and playing back methods out of sync... so, first off I have a recorder interface:
public interface IRecorder
{
bool IsPlayback { get; }
void RecordMethod(MethodInfo method, object[] parameters);
}
Following that I implemented a base class for recording the methods, and allowing for playback:
public class BaseRecorder : IRecorder
{
private readonly List<RecordedMethod> _methods = new List<RecordedMethod>();
private bool _isPlayback;
#region IRecorder Members
public void RecordMethod(MethodInfo method, object[] parameters)
{
_methods.Add(new RecordedMethod(method, parameters));
}
public bool IsPlayback
{
get { return _isPlayback; }
}
#endregion
public void Playback()
{
try
{
_isPlayback = true;
foreach (RecordedMethod method in _methods)
method.Replay(this);
}
finally
{
_isPlayback = false;
}
}
#region Nested type: RecordedMethod
public class RecordedMethod
{
private readonly MethodInfo _method;
private readonly object[] _parameters;
public RecordedMethod(MethodInfo method, object[] parameters)
{
_method = method;
_parameters = parameters;
}
public void Replay(object instance)
{
_method.Invoke(instance, _parameters);
}
}
#endregion
}
Pretty basic - then I wrote myself the aspect - it really could not be simpler:
[Serializable]
public class MethodRecordAttribute : OnMethodInvocationAspect
{
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
{
IRecorder recorder = (IRecorder) eventArgs.Delegate.Target;
object[] arguments = eventArgs.GetArguments();
if (recorder.IsPlayback) eventArgs.Delegate.DynamicInvoke(arguments);
else recorder.RecordMethod(eventArgs.Delegate.Method, arguments);
}
}
And finally a demo... so I create a recorder class of my very own and decorate it with the attribute created above:
[MethodRecord]
public class MyRecorder : BaseRecorder
{
public void SayHiTo(string name)
{
Console.WriteLine("Hi {0}", name);
}
public void AddSomeNumbers(int x, int y)
{
Console.WriteLine("{0} + {1} = {2}", x, y, x + y);
}
}
And now a quick demo:
[TestFixture]
public sealed class TryOutPostSharp
{
[Test]
public void RecordAndPlayback()
{
MyRecorder recorder = new MyRecorder();
Console.WriteLine("Starting to record");
recorder.SayHiTo("Alex");
recorder.SayHiTo("Renee");
recorder.SayHiTo("Blog subscribers");
recorder.AddSomeNumbers(10, 20);
Console.WriteLine("Starting to replay");
recorder.Playback();
Console.WriteLine("All done");
}
}
The output is: Starting to record Starting to replay Hi Alex Hi Renee Hi Blog subscribers 10 + 20 = 30 All done
Which I think is pretty darn sweet, I can definitely see this having a place in my toolbox in the near future - especially when attempting to uphold DRY in some of my code - anyone using it on production projects in NZ at the moment? So how does PostSharp pull it off? Well it post-processes the compiled assembly... it does so by hooking in to an existing extension point in msbuild, so that the post-processor is executed for any project where it references the PostSharp.Public assembly. All this means that you get to see a couple of extra lines in the build output during compilation: Compile complete -- 0 errors, 0 warnings PostSharp 1.0 [1.0.7.261] - Copyright (c) Gael Fraiteur and Community, 2005-2007. TryPostSharp -> C:\dev\experiments\TryPostSharp\TryPostSharp\bin\Debug\TryPostSharp.dll ========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
But how does it really work? Well if we take a look at the list of 7 approaches to AOP Ayende did ... then it fits into the last two (Compile-time & Run-time IL Weaving). If you have been living under a rock like myself I'd definitely suggest talking 10 minutes out of your day to give it a quick try.
 Thursday, July 26, 2007
About to run off to a meeting... so I'll make this quick. Just read an interesting post by Donald Belcham on Refactoring Analysis with the help of nDepend... he's gone through the process of moving from .Net 1.1 to 2.0, then introducing interface based code, breaking classes apart to ensure they're enforcing the principle of single responsibility, moving to injecting dependencies, rolling his own primitive Inversion of Control container and finally employing the Castle Project's windsor container instead. It pays to know a little bit about nDepend of course to understand the Abstractness vs Relational Cohesion figures... either take a look at the nDepend site, or maybe have a listen to the .Net Rocks podcast earlier this year which covered the same topic. I'm not sure the figures actually answer questions so much as they ask them ... but it's interesting to see how much impact his first two rounds of refactoring had on the results. I wonder how the figures would've come out had he executed his refactoring in a different order... maybe DI first, then breaking the classes up based on responsibility, IoC and then finally introducing interfaces... hmmm
 Tuesday, July 24, 2007
So IronRuby has been released in a pre-alpha state... check out the comments on John Lam's post for some additional details not in the post itself.
c:\dev\resources\IronRuby-Pre-Alpha1\Bin\Release>rbx.exe
IronRuby Pre-Alpha (1.0.0.0) on .NET 2.0.50727.312
Copyright (c) Microsoft Corporation. All rights reserved.
>>> class RubyAlpha
... def hello
... puts "Hello"
... end
... end
=> nil
>>> r = RubyAlpha.new()
=> #<RubyAlpha:0000002b>
>>> r.hello
Hello
=> nil
>>>
Things of interest: - Lots of stuff doesn't work just yet ;o)
- it will end up on Rubyforge, not Codeplex... and I think it's quite an appropriate decision considering the nature of the project... good to see common sense winning over marketing dogma - and it's going to be there by the end of August.
- The project will eventually be entirely open to community contributions (I don't think that includes the code making up the DLR itself, as a shared platform that's probably something that needs to be tightly controlled)
 Friday, July 20, 2007
So, big congratulations to Alex J - first an MVP and now a Microsoft employee to boot... (which I suspect trumps his MVP status, probably should be MV E now, for Employee!). I've been working with Alex (2 Alex's... very confusing) on a pretty interesting project for the last couple of months, and it's been a lot of fun getting a brain dump from a guy who's so passionate about technology (and community too) and with so many varied and original ideas... Whenever Alex J starts a sentence with " now I've been putting some thinking around this" you generally know your about to learn something cool :) On a side note, I'm thinking of taking over the organization/blogging etc. of the Sylvia Park Architecture Chats in the other Alex's absence... It would be a real shame to let it die once Alex J has moved to the states... at any rate, something to talk about this coming Thursday at the next chat!
 Saturday, July 14, 2007
Wasted 5 minutes figuring out what was going wrong, maybe this will save someone else the effort! When using RhinoCommons and CastleProject both from trunk there's a version conflict with NHibernate. RhinoCommons has NHibernate Version 2.0.0.1001 (Including support for things like Multi-criteria) ... and then the Castle Project is using NHibernate Version (1.2.0.4000) - this took me a little bit by surprise when I discovered that a monorail project I had was failing when attempting to databind properly when using the ARSmartDispatcherController... because I wasn't checking the binding errors collection, this was just failing silently... so a save would just load/save the existing record, without any binding. Quick fix is just to use a assembly binding redirect in the web.config:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<publisherPolicy apply="no"/>
<dependentAssembly>
<assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" culture="neutral" />
<bindingRedirect oldVersion="1.2.0.4000" newVersion="2.0.0.1001"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
 Thursday, July 05, 2007
So I see both Andrew, Nick and Alex J have some thoughts on languages, and of course Rowans post sparked it off... and people talk about beautiful languages, mentioning expressiveness in the same breath. Personally I love how expressive Ruby is - I think potentially because I got my first exposure to ruby after reading Why's poignant guide a while back (I see there are new chapters ...oooh) which was quite surreal compared to how I say learnt C++ (from reading the Borland Turbo C++ manual when I was 11, also my first exposure to OOP)... When I code in ruby I feel like I'm telling stories... I dig that :) So Alex J mentioned that extension methods let us achieve much of the syntactic sugar that ruby provides (though obviously in ruby's case this isn't so much syntactic sugar as core mechanisms in the language itself) - and of course Lambda expressions are helping too, but does expressive == good 100% of the time? I don't think I'm qualified to say, but I can't help but feel that a language which is very expressive, isn't necessarily the easiest to manipulate and refactor, so I may not be as productive and it may not feel as fluent to me... I quite liked this resharper horizons post which suggests that tooling support should probably influence future language design - could that requirement possibly fight against an increased level of expressiveness in a language, will compromises need to made, or is nirvana just around the corner? As for C# vs VB.Net - large clumsy keywords are only a probablem until something like Resharper steps in... when I'm developing I see a lot of unusued space on the right hand side of the editor with C#... if VB.Net fills it up, and I'm not typing any harder to get there, why should I care - hell it'll probably make a VB.Net Resharper Jedi look more impressive then the C# equivalent, he'll be producing more characters ;o) OK, well I figured this post should at least have some code... I'd feel uneasy otherwise... so how about:
public static class CommonExtensions { public static Action<Action<int>> LoopTo(this int start, int end) { return new Action<Action<int>>(action => To(start, end).ForEach(i => action(i))); } public static IEnumerable<int> To(this int start, int end) { if (end < start) for (int i = start; i > end - 1; i--) yield return i; else for (int i = start; i < end + 1; i++) yield return i; } public static void ForEach<T>(this IEnumerable<T> sequence, Action<T> action) { foreach (T item in sequence) action(item); } public static void PrintLine(this object o) { Console.WriteLine(o); } }
So now we could try and do this....
// ruby (10..20).each { |i| puts i }
// C# 10.LoopTo(20) ( i => i.PrintLine() );
Alas I don't think C# will ever match ruby in this game, no matter how we try to nudge it there... and until the development community figures out where the healthy place is to draw the line in the attempt, we may be doing more harm then good by pushing for it, sacrificing discoverability/maintainability for expressiveness. Maybe that's just dogma, and expressiveness makes code inherently easier to maintain in the first place, so we don't need to care.... time will tell. Of course I could be wrong, I am a little sleepy ;o)
 Tuesday, July 03, 2007
So I've tidied up the source for the DSL from my last post a little... though my "test" was to represent a DSL similar to the one Ayende displayed in Brail - I haven't implemented any monorail view engine integration, there's little point I feel, I was more interested in being able to display a nested DSL-like syntax, and parse the necessary information out of it as required.
You can grab it from SVN repository here (edit: I've now fix the PROPFIND proxy issue, so the link should work)
At any rate, probably the most interesting example is the one that takes this code:
var people = new List<Person>()
{
new Person() { FirstName = "Alex", LastName = "Henderson"},
new Person() { FirstName = "Joe", LastName = "Bloggs"}
};
var compDsl = new ComponentDsl();
compDsl.Add
(
GridComponent => compDsl.Component
(
compDsl.Parameters
(
source => people
),
header => compDsl.Section
(
tr => compDsl.As
(
th => compDsl.As
(
compDsl.Text("Names")
)
)
),
item => compDsl.Section
(
tr => compDsl.As
(
td => compDsl.As
(
compDsl.Item<Person>(p => p.FirstName + " " + p.LastName)
)
)
)
)
);
var dsl = new StandardDsl();
dsl.Add
(
html => dsl.As
(
body => compDsl
)
);
And converts it to this xhtml...
<html>
<body>
<table>
<tr>
<th>Names</th>
</tr>
<tr>
<td>Alex Henderson</td>
</tr>
<tr>
<td>Joe Bloggs</td>
</tr>
</table>
</body>
</html>
You can pretty quickly figure out what's going on by placing a breakpoint on the Execute() method of the StandardDsl class and tracing through all the calls - in essence all the nodes are emitted by calling the top-level Batch delegate which causes a recursive call down the "tree", with the information being emitted as a side-effect to an evaluation scope.
Though I used nodes - effectively creating a structure that's easier to parse, there's no reason why you couldn't make immediate calls to some kind of object, avoiding the need for a second round of parsing - the only trick is that you'd still need to use some kind of scoped stack to push/pop the names of the components because in a statement like this:
dsl.As
(
GridComponent => dsl.Component
(
// etc. etc.
)
)
the call to dsl.Component needs some way to inspect the stack of names and pull "GridComponent" off the top.
I'd love to hear from anyone who could see a use for this kind of thing... it'd be nice to get a more realistic example... I'm struggling to think of anything practical myself. [Edit: I Noticed the code formatting was pretty awful, so I've tidied it up a little... anyone got a good solution for copy/pasting code out of orcas (CopyAsHtml2005 doesn't appear to install under Orcas)]
 Friday, June 29, 2007
Following on from my posts on creating hashes (dictionaries) using lambdas (here, and here) and the little annotations "framework" I produced (here and here) which leverage the idea for annotating classes via extension methods... I've decided to turn my hand to creating a DSL using lambdas, on my continuing theme of C# 3.0 lambda abuse.
So first off... go have a look at Ayende's post DSL Support for brail ... that'll give you an idea of kinda what I'm trying to achieve.... so, here's an example of a simple DSL for building say a html table.
var dsl = new StandardDsl();
dsl.Add( table => dsl.As( tr => dsl.As( td => dsl.Text("header1"), td => dsl.Text("header2"))));
Console.WriteLine(DslToXml.ToXml(dsl));
which gives an output of:
<table><tr><td>header1</td><td>header2</td></tr></table>
Depending on taste you could lay it out differently, avoiding the mess of closing parentheses at the end of the Add call, say like:
var dsl = new StandardDsl();
dsl.Add ( table => dsl.As ( tr => dsl.As ( td => dsl.Text("header1"), td => dsl.Text("header2") ) ) );
Which is pretty easy on the eyes... now what about something a little more domain specific like the view component example Ayende gave for monorail... well here's my take on that, so say we have some people:
var people = new List<Person>() { new Person() { FirstName = "Alex", LastName = "Henderson"}, new Person() { FirstName = "Joe", LastName = "Bloggs"} };
And we have a DSL specific to components...
var compDsl = new ComponentDsl();
compDsl.Add ( GridComponent => compDsl.As ( compDsl.Component(source => people), header => compDsl.Section ( tr => compDsl.As ( th => compDsl.As ( compDsl.Text("Names") ) ) ), item => compDsl.Section ( tr => compDsl.As ( td => compDsl.As ( compDsl.Item<Person>(p => p.FirstName + " " + p.LastName) ) ) ) ) );
And now we could do this in-line with a bigger DSL for say a whole view, but we can also just reference them so I could do something like this to create the overall view:
var dsl = new StandardDsl();
dsl.Add ( html => dsl.As ( body => compDsl ) );
Now once I've tidied the code up a bit I'll probably put it up for people to have a play with - I don't necessarily consider a "good idea" - but it's cute. However for now let's have a quick look at how I'm doing it...
So to start with we have a delegate called "Batch" with the signature below - batch probably isn't the right name for this, I'm not really sure it matters all that much.
public delegate Batch[] Batch(Batch batch);
Batch takes a Batch and returns an array of Batch ;o) and to match that we then have say the "As" method on the DSL:
public Batch[] As(params Batch[] batches) { Batch asBatch = new Batch(delegate(Batch ignore) { ExecuteBatches(batches); return null; }); IgnoreBatch(asBatch);
return new Batch[] { asBatch }; }
Notice it takes one or more Batch instances, and returns a delegate which executes the batches, ignores the batch we just generated and returning the one Batch as an array... conforming to the expected return type of the Batch delegate. Clear as mud? ;o)
Ignoring the batches actually just uses the annotation framework, so IgnoreBatch looks like this:
public void IgnoreBatch(Batch batch) { batch.Annotate(Ignore => true); }
And then we check if a batch is ignored before processing it down the line by calling this method.
public bool IsBatchIgnored(Batch batch) { return batch.HasAnnotation("Ignore"); }
Last of all to actually "render" the DSL into some useful format we execute it (no Expression<>'s required, so it's very fast) ... which just call the top with null, which in turn calls the arguments, and those arguments arguments etc. While doing that we write nodes (much like an Xml writer) against an "evaluation" scope, which associates a NodeWriter with the current thread.... basically the DSL ends up as a bunch of calls like:
NodeWriter writer = new NodeWriter(); writer.WriteStartNode(new NamedNode("table")) .WriteStartNode(new NamedNode("tr")) .WriteStartNode(new NamedNode("td")) .WriteNode(new TextNode("column1")) .WriteEndNode() .WriteEndNode() .WriteEndNode();
where the nodes conform to this interface:
public interface INode { INode Parent { get; set; } List<INode> Nodes { get; } }
At which point it's trivial to walk the tree of INode's and do whatever you like with the information stored within it, and we can encapsulate new concepts by creating new types of node, which have payloads of additional information.
At any rate, next time I'll post a little more about how I'm doing it, and attach the code for people to have a play with.
No so much for my future reference, but to refer people too should the topic of how generic types are represented by name ever crops up again.
| Type |
FullName |
| typeof (List<>).FullName |
System.Collections.Generic.List`1 |
| typeof(List<int>).FullName |
System.Collections.Generic.List`1[[System.Int32]] |
| typeof(Dictionary<,>).FullName |
System.Collections.Generic.Dictionary`2 |
| typeof(Dictionary<string,int>).FullName |
System.Collections.Generic.Dictionary`2[[System.String],[System.Int32]] |
| typeof(Dictionary<string,List<int>>).FullName |
System.Collections.Generic.Dictionary`2[[System.String],[System.Collections.Generic.List`1[[System.Int32]]]] |
|
 Thursday, June 14, 2007
Here's the code for my last post on Annotations - I tidied up a few things up (it's still very basic but it does work) there's a single test fixture to give you a guide for usage... so things like:
[Test] public void QueryStoreForClassAnnotationsWithCertainKey() { ClassA target1 = new ClassA(); ClassA target2 = new ClassA(); ClassA target3 = new ClassA();
target1.Annotate(Description => "class number 1"); target2.Annotate(Description => "class number 2"); target3.Annotate(Parsed => true);
var results = AnnotationStore.Classes .Where(a => a.HasKey("Description")) .ToList();
Assert.AreEqual(2, results.Count); }
And also the equivalent thing is possible for members... though I suspect annotating members isn't all that useful in most cases...
[Test] public void QueryStoreForMemberAnnotations() { ClassA target1 = new ClassA(); ClassA target2 = new ClassA(); ClassA target3 = new ClassA();
target1.Annotate(() => target1.FirstName, CamelCase => true); // annotating a property target1.Annotate(() => target1.Field, Ignored => true); // annotating a field target2.Annotate(() => target2.Execute(), Parsed => true); // annotating a method
target3.Annotate(Parsed => true);
var results = AnnotationStore.Members .Where(p => p.HasKey("CamelCase")) .ToList();
Assert.AreEqual(1, results.Count); }
So I've been mulling some ideas over after the whole abusing lambdas for Hash table construction (here and here) ... and after reading a post on Jb Evain's blog I decided to create a little bit of code for doing annotations... so given a class say:
public class ClassA { public int Id { get; set; } public string Name { get; set; } }
You can then do this kind of thing (assuming you've added the apropriate namespace where the Annotations static class resides in)
[Test] public void AnnotateClass() { ClassA classA = new ClassA(); classA.Annotate(IsValid => false); classA.Annotate(MapsToTable => "TblClassA", Key => "Id"); classA.Annotate(Roles => new [] {"Administrator", "User"});
Assert.IsFalse(classA.Annotation<bool>("IsValid")); Assert.AreEqual("TblClassA", classA.Annotation<string>("MapsToTable")); Assert.AreEqual("Id", classA.Annotation<string>("Key")); }
Or, perhaps you want to attach some annotations to a specific property... no problem!
[Test] public void AnnotateProperty() { ClassA classA = new ClassA(); classA.Annotate(() => classA.Name, CanBeNull => true); bool canBeNull = classA.Annotation<bool>(() => classA.Name, "CanBeNull"); Assert.AreEqual(true, canBeNull); }
Under the hood the values are stored against a dictionary where the keys (in this case the instance of classA) are weak referenced... so once classA is garbage collected the entries in the dictionary will also dissapear in time (next time any method touches the dictionary). The nice thing is obviously you can directly interogate the Annotations static class itself with a query expression to say find all objects with a certain annotation.
 Tuesday, June 12, 2007
So, I got a comment on the last post about hashes from lambdas (from Andrey Shchekin)... It pointed out the fact that you don't need to use expressions at all... which hilights an observation that I hadn't made myself - such that the lambda parameter names are available in the generated delegate... which of course makes perfect sense!
So given:
Func<string, T> func = Name => "Value";
You can get the lambda parameter "Name" from the function delegate by calling:
func.Method.GetParameters()[0].Name (would return "Name")
Here's the revised Hash method from Andrey:
public Dictionary<string, T> Hash<T>(params Func<string, T>[] args) where T : class { var items = new Dictionary<string, T>(); foreach (var func in args) { var item = func(null); items.Add(func.Method.GetParameters()[0].Name, item); } return items; }
very elegant and simple :)
He even did some stats, which I suspect are probably a lot more accurate then my inital observations:
For 10000 consecutive calls:
| WithAdd |
10.0144ms |
| WithLambdas |
9713.968ms |
| WithLambdasConstantsOnly |
240.3456ms |
| WithDelegates |
30.0432ms | Now what about multiple parameters... so far I can't think of any uses I would have for it... perhaps a 2 level configuration dictionary?
[Test] public void HashTwoLevelDict() { Dictionary<string, Dictionary<string, object>> config = this.Hash<object>( (Connection, DriverClass) => typeof(SqlClientDriver), (Dialect, DialectClass) => typeof(MsSql2000Dialect), (Connection, Provider) => typeof(DriverConnectionProvider), (Connection, ConnectionString) =>"Data Source=.;Initial Catalog=test;Integrated Security=SSPI");
Assert.AreEqual(typeof(SqlClientDriver), config["Connection"]["DriverClass"]); } Who knows... I look forward to seeing how Lambdas get used and abused for non-functional programming tasks :)
 Monday, June 11, 2007
So first off... I'm surely not the first person to see the resemblance between a lambda expression and a hash table declaration in Ruby... so I had a go at populating a dictionary using lambda's... so given this:
[Test] public void Evaluate() { Dictionary<string, string> items = Hash(Name => "alex", Age => "10", Height => "20"); Assert.AreEqual("alex", items["Name"]); Assert.AreEqual("10", items["Age"]); Assert.AreEqual("20", items["Height"]); }
I got my desired result pretty quickly...
public Dictionary<string, T> Hash<T>(params Expression<Func<string, T>>[] args) where T: class { Dictionary<string, T> items = new Dictionary<string, T>(); foreach (Expression<Func<string, T>> expression in args) { ConstantExpression itemValueExpression = expression.Body as ConstantExpression; if (itemValueExpression == null) throw new InvalidCastException("The body of the expression must be of type ConstantExpression"); T item = itemValueExpression.Value as T; items.Add(expression.Parameters[0].Name, item); } return items; }
But, then I tried this...
[Test] public void EvaluateForObjects() { Dictionary<string, object> items = Hash<object>(Name => "alex", TargetType => typeof(Uri), Id => 10); Assert.AreEqual(10, items["Id"]); }
Which fails, the last key/value pair (Id => 10) isn't represented as a ConstantExpression, so to support it (and other eventualities) I modified my code a smidge...
public Dictionary<string, T> Hash<T>(params Expression<Func<string, T>>[] args) where T: class { Dictionary<string, T> items = new Dictionary<string, T>(); foreach (Expression<Func<string, T>> expression in args) { ConstantExpression constantExpression = expression.Body as ConstantExpression; T item = null; if (constantExpression != null) { item = constantExpression.Value as T; } else { item = Expression.Lambda<Func<T>>(expression.Body).Compile()(); } items.Add(expression.Parameters[0].Name, item); } return items; }
Now... let's compare performance to say, adding the values using the Add method... so... for a million consecutive executions (in milliseconds) a quick test yielded these results...
| Execution # |
Using 'Hash' |
Using Dictionary.Add() |
| 1 |
9718 |
1268 |
| 2 |
9588 |
1310 |
| 3 |
9636 |
1494 |
Which I suspect tells me nothing more then the fact that the "Hash" style initialization is a lot slower, but not slow enough to completely discourage me. Edit: There seems to be a bit of interest in this lately, so don't forget to take a look at the other related posts if you found this interesting.
 Thursday, May 03, 2007
So looking at Astoria very briefly today ... a good starting point is probably Alex James blog and all the linked posts - and so far I'm left with a "so what" attitude to the technology releases so far (but it is very early days). I feel like what's being presented is something I could cobble together using Dream and ActiveRecord/ NHibernate or Base4 with a couple of weeks work at best... I'm probably being a little optimistic though ;o) Devil is always in the detail... but what's in the wild so far hasn't made me sit up and take notice, I hope the next couple of drops will though. However in the mean time, what does interest me: - Standardization of a query scheme... so far I've only seen examples of search/get queries.. I'm particularly interested in any update related queries... this is where the opportunities for doing evil live, and where community input will be vital I think.
- How does WebDAV fit into the Astoria picture at the moment?
- Astoria SaaS ... I find the idea of being able to design and provision REST'ful stores on the web (with my own schema) quite intriguing.
- That said - I'm not sure what I'd do with it, but I still want it ;o)
- And thinking out loud, but besides the obvious uses for web/ajax/flash/silverlight fraternity *yawn* - could this kind of thing actually give new life to some desktop based applications - It could certainly smarten them up a bit, so that using the same application on multiple machines (i.e. work/home) could optionally give you the same experience.
 Monday, April 30, 2007
Been doing a little WCF today... I augmented a partial message class on a client with some additional properties, including this:
private bool _partOfResults = true;
public bool PartOfResults
{
get { return _partOfResults; }
set { _partOfResults = value; }
}
Now I assumed by default the any messages would have PartOfResults set to true... just like it used to work with ye olde XmlSerializer ;o) But actually no ... WCF doesn't invoke the constructor - surprised I hadn't noticed until now - particularly annoying is of course my unit tests were passing because I was calling the default constructor on the message... so first of all I decided to cheat and just implement the method like this:
private bool _partOfResults;
public bool PartOfResults
{
get { return !_partOfResults; }
set { _partOfResults = !value; }
}
But I didn't like the implications ;o) so I went and actually looked up how to make it work properly:
[OnDeserialized]
private void InitializeExtraFields(StreamingContext context)
{
_partOfResults = true;
}
Pretty boring ;o) just surprised me because I haven't done much WCF since it went final.
 Thursday, March 29, 2007
If you have to make your own license keys i.e. ABCDE-ABCDE-ABCDE-ABC1Z-A32DE Here's some thoughts/ideas for things you can do to break up the key space a little so people can not easily brute-force your keys by fiddliing just a couple of numbers. - Select a range of numbers and letters that can be directly mapped to 32 values (10 digits and 22 alpha maybe?).
- Know your maths.. creating helper classes for unpacking and packing bytes will help.
- In this example you could carry 125bits (15 bytes and just over a nibble ;o) ... or 13 bytes + CRC16 (or Maybe an Adler16).
- Use lookup tables to translate sequential values into pseudo-random values.
- Break any multi-byte values up into individual bytes, stuff em around your payload of bytes in non-sequential offsets.
- Calculate the CRC for your payload and include it as part of the key's data, verify it when you're decoding.
- You can use structs with a sequential layout and a packing of 1 to define your structure...
- Use Marshal.Copy etc. methods to copy between the struct and a byte array.
- Remap individual bits in the overall payload.
The last one is something that works really well... it's hard to avoid certain digits "sticking" when generating sequential keys no matter what you do... but if you remap the individual bits of a 15 byte array (i.e. using a lookup table containing 120 indexes) you end up with very unique looking keys that have no sequential behaviour to them (especially if you redistribute the bits of the CRC into all the bytes of the key, which in turn are repacked into 5 bit letters).
 Tuesday, March 06, 2007
Have you ever wanted to be able to do something like this in C#? string propertyName = GetName(MyClass.MyProperty);Well I have, in fact I've wanted the ability to do this since Version 1 of the .Net Framework, and now with C# 3.0 we finally can! First off, check out the original blog post here - Symbols in C# 3.0 by Jafar Husain - it's a clever (and once I thought about, plainly obvious) use of extension methods and expression trees.
public static class SymbolExtensions
{
public static string GetPropertySymbol<T,R>(this T obj, Expression<Func<T, R>> expr)
{
return ((System.Linq.Expressions.MemberExpression) (((System.Linq.Expressions.LambdaExpression)(expr)).Body)).Member.Name;
}
}
Usage requires a lambda, but that's not to painful, here's example usage:
MyClass o;
//...
string propertyName = this.GetPropertySymbol(o => o.MyProperty)
The beauty of this is that refactoring is entirely painless, you don't need to spend time reviewing all the optional string replacements that resharper may have found in case you haven't mirrored a property or method name change correctly... it also looks like it could offer some nice usability improvements to some unit testing scenarios (nothing worse then unit tests that don't seamlessly refactor with your code). I wonder what other ideas are floating around for expression trees at the moment (outside of the obvious querying concepts) ?
 Saturday, March 03, 2007
Dumping eventsI'm often surprised (or is it dismayed) when questions pop up in news groups surrounding things like event orders for winforms or webforms applications... this isn't rocket science... we're given all the tools to make this easy to figure out! Lets do a winforms 2.0 app as an example... first off, the earliest point at which can easily get involved is the constructor... lets have a look:
public partial class Form1 : Form
{
public Form1()
{
AttachToAllEvents();
InitializeComponent();
}
So I'm going to attach to all the events before the forms components are initialized... now lets have a look at the " AttachToAllEvents" method.
private void AttachToAllEvents()
{
Type type = GetType();
foreach (EventInfo info in type.GetEvents())
{
string eventName = info.Name;
EventHandlerWrapper wrapper = new EventHandlerWrapper(new EventHandler(
delegate
{
Console.WriteLine("{0}: EventName: {1}, IsVisible: {2}, IsHandleCreated: {3}, HasChildren: {4}, IsDisposed: {5}",
DateTime.Now, eventName, this.Visible, this.IsHandleCreated, this.HasChildren,
this.IsDisposed);
}));
wrapper.Attach(this, info);
}
}
Only magic there is we're using a class called " EventHandlerWrapper" - what's that... well, it's used to create a strongly typed delegate for attaching to an event. The reason we need this at all is because EventInfo.AddEventHandler(...) is fussy about the kind of delegate you supply, so if you pass in an " EventHandler" for a " CancelEventHandler" event, it'll throw an exception complaining about it's inability to cast between them... there might be an easier way to do this, but I haven't come across it so far.
public class EventHandlerWrapper
{
private EventHandler _handler;
private static readonly MethodInfo _methodInfo;
static EventHandlerWrapper()
{
_methodInfo = typeof(EventHandlerWrapper).GetMethod("InvokeHandler", BindingFlags.NonPublic | BindingFlags.Instance);
}
public EventHandlerWrapper(EventHandler handler)
{
if (handler == null) throw new ArgumentNullException("handler");
_handler = handler;
}
public void Attach(object target, EventInfo info)
{
Delegate wrappedHandler = Delegate.CreateDelegate(info.EventHandlerType, this, _methodInfo);
info.AddEventHandler(target, wrappedHandler);
}
private void InvokeHandler(object sender, EventArgs args)
{
_handler(sender, args);
}
}
With a little brain power I'm sure I could've done this without the separate wrapper class, but this is probably a little easier to read at any rate. Results..?So.. onto the results - once we run the code and see exactly what order events are happening in, we can then make a pretty table that may not render in most browsers because I cut 'n pasted it from Excel 2007 ;o)
| EventName |
IsVisible |
IsHandleCreated |
HasChildren |
IsDisposed |
| Resize |
False |
False |
False |
False |
| SizeChanged |
False |
False |
False |
False |
| ClientSizeChanged |
False |
False |
False |
False |
| ClientSizeChanged |
False |
False |
False |
False |
| ControlAdded |
False |
False |
True |
False |
| ControlAdded |
False |
False |
True |
False |
| StyleChanged |
False |
False |
True |
False |
| TextChanged |
False |
False |
True |
False |
| Move |
False |
True |
True |
False |
| LocationChanged |
False |
True |
True |
False |
| HandleCreated |
False |
True |
True |
False |
| Invalidated |
False |
True |
True |
False |
| StyleChanged |
False |
True |
True |
False |
| ChangeUICues |
True |
True |
True |
False |
| Invalidated |
True |
True |
True |
False |
| BindingContextChanged |
True |
True |
True |
False |
| Load |
True |
True |
True |
False |
| Layout |
True |
True |
True |
False |
| VisibleChanged |
True |
True |
True |
False |
| Activated |
True |
True |
True |
False |
| Shown |
True |
True |
True |
False |
| Paint |
True |
True |
True |
False |
| Paint |
True |
True |
True |
False |
| Paint |
True |
True |
True |
False |
| MouseCaptureChanged |
True |
True |
True |
False |
| Closing |
True |
True |
True |
False |
| FormClosing |
True |
True |
True |
False |
| Closed |
True |
True |
True |
False |
| FormClosed |
True |
True |
True |
False |
| Deactivate |
True |
True |
True |
False |
| HandleDestroyed |
True |
True |
True |
False |
| Disposed |
False |
False |
False |
False |
The main thing to keep in mind when doing something like this is to avoid making assumptions - we may not be the first or last to attach to the events (depending on the complexity of the form) - and events can trigger other events... which could explain the ordering of some of this data i.e. changes in visibility and handle creation... if anything we are viewing the order of consequences, as opposed to the true order in which the events are invoked (to get that we'd need to override all the OnXXXX methods of the form class... which would be a good job for dynamic proxy :)
 Friday, February 23, 2007
Changes in the wind...I'm looking at expanding my operation ( Dev Defined Limited) - after having come to the conclusion that I can't support my current client base, and certainly can't offer them enough business continuity should I be put out of action - short of taking key man insurance out on myself ;o) - I need to start growing. At any rate I've decided to do a few things: - Start engaging old clients (and finding new clients) to queue up more work beyond my capacity.
- Taking on additional staff to both do that work, and transfer knowledge about existing clients and solutions.
Which brings me to the point of this post, I'm going to be looking for a couple of additional development staff (both senior). So if you're a flexible senior developer, with a strong .Net background who wants to help build a development shop up, and is looking for opportunities to stretch their legs and play with some new and interesting technologies (instead of just reading about them on blogs) then why not drop me a line? Our projects cover a wide variety of areas, looking back over the past 8 months some of the more interesting bits of work have been: - A client server system for audio identification, using WCF, Base4.Net with a Monorail based web front-end.
- Rich message processing system for Seismic Technologies, a large solution that included a rich winforms based remote configuration interface, integrated IronPython scripting, heavy use of dependency injection, WSE 3.0 and IoC.
- Library for media transformations (designed to plug-in to the SyzmkRMP product, but also for other users) - including an Audio/Video encoding library that wraps up DirectShow.Net which was open-sourced as the Splicer project on codeplex.
Starting package would be $85K + 5 weeks holiday, Pay review after 6 months. And on the flip-side of that coin, I'm looking for additional project/product development work to take on board, so if you have a project that you think would benefit from our unique set of skills and experience and a team of developers with a focus on innovative solutions, drop us an email.
 Tuesday, February 20, 2007
Came across a short piece I wrote about IronPython while looking for something else - it was in response to some questions from Kathleen Richards in September of last year for Redmond Developer News (which I think was for this Article, though none of the content made it in - cest la vie). At any rate, I figure I might as well post it here, it may be of use to someone... somewhere... who could say? Looking over it briefly I'm not even sure I agree with some of the points I made any more :P
IronPython Article How are you using IronPython?
At Syzmk ( http://www.syzmk.com/) we are using IronPython as a rich embedded scripting language within our core product, we expose a large part of the .Net server engine (written in C#) to the IronPython runtime, and offer key extension points which can be hooked into with python code – we chose python because the language is rich, dynamic and doesn’t suffer from the verbosity that most of the compiled languages do. At the moment we are moving beyond using IronPython as just an embedded scripting language and are evaluating how best to implement a number of domain specific languages in it for our server, firstly around the business rules and behavior of our application’s core logic, and secondly for performance and diagnostic evaluation and control of the underlying server platform. Why did you choose this implementation over C python or Jython or other dynamic languages? IronPython was attractive because of its first class support for .Net types and especially its excellent support for delegates (and because there wasn’t any marshalling) – we were attracted to the python syntax and language structure, more than support for the standard python libraries, so the compatibility sacrifices that were apparent with many C Python libraries, especially during the beta, were of little consequence to us, especially as IronPython has full access to the base class libraries (BCL). What types of applications are you building? The core application we have used IronPython for is a server technology, the “Rich Media Processor” (working title) – it’s in production, but has only been going to market for the last 6 months. Effectively you can place it into an organization as a front end processor for rich and largely unstructured messages (think Audio, Video, Email, SMS and MMS messages from phones, images dumped from digital cameras, security camera feeds etc) with the end result being a structured and conforming set of messages and rich content (appropriately formatted images, videos, audio etc) suitable for passing onto line of business systems, or a product like biz talk. When dealing with transforming this kind of content, python (and IronPython) is a great language to augment the message transformation process – strong string support, access to all the functionality of our underlying application and it’s easy to develop and deploy – IronPython never seems to be working against us, I could never claim the same for any scripting language I’ve implemented into a product before. Does the .NET environment offer any advantages?Yes, I think it offers serious advantages for Python (access to the BCL!), developers and customers. First off the business case for building .Net applications is immediate within our home country of New Zealand, customers are generally expecting to host Microsoft tools and solutions, and our IT industry is geared towards this expectation, there is an implied trust which is worth taking advantage of. Business cases aside however I think the .Net platform is very engaging for us, our company has a love for technology, and in the last few years the .Net platform has been satisfying that need very well - it offers stability, security and productivity increases that we can’t find elsewhere (and certainly not in an unmanaged language), also the language-agnostic approach and ability to build dynamic languages (like IronPython) in the CLR make the choice all that simpler. Disadvantages?We haven’t really discovered any disadvantages with .Net or our approach, IronPython does everything we need and then some, as does the .Net platform – however I think it might be some time yet before dynamic languages on the CLR (or any language other then VB.Net or C#) will be acceptable recommendations from the consulting masses – perhaps more a reflection on the lack of education and published case studies I think. For instance we already have languages competing with C# on the .Net platform, such as Boo ( http://en.wikipedia.org/wiki/Boo_programming_language), which offer some advantages over the current version of C# and are very suitable for building domain specific languages (DSL’s) – but I believe in many bespoke development houses it would be very hard to get buy-in for using these languages in upcoming projects, even if they will save time and money or just be a better fit for their problems. Do you think dynamic, object oriented (scripting) languages (Ruby, Python) will start to play a larger role in enterprise development? I think the short answer is yes, the languages are often just a catalyst for methodologies and practices (such as functional programming, or the ruby on rails web development approach) – the elegance, simplicity and speed at which dynamic language guru’s can deliver results is enviable for a lot of us who have cut our teeth on C++ & Java and known the other end of the spectrum. If I am in a corporate environment should I be looking into these languages? I think at this point it should not be on the top of your list – if you’re a Microsoft shop, or in an environment dedicated to employing solutions on top of Microsoft technologies then .Net 3.0 should be your key focus - however I think it’s certainly worth having a few dynamic language books at your disposal (perhaps on the bedside table), they make for compelling reading, and will get your initial buy-in, so you feel comfortable considering a dynamic language on the .Net platform as a good idea. That said, if you’re not a Microsoft shop, and particularly if you are committed to open-source technologies I would look seriously, probably first at Ruby, it’s very engaging story – though of course you can run IronPython on Mono with a little bit of tweaking … and IronRuby is getting better every day. What are some of the key issues from an application development standpoint?I can only talk from the perspective of deploying IronPython as a scripting engine, hosted within another application, though some of these points will probably apply elsewhere, I think it all comes down to one thing - being prepared. First off, you must change your point of view and adapt some of your practices, as they will confound you with the introduction of a scripting language that has access to your own .Net classes. As you develop classes, try them on for size and make sure the selected scripting language doesn’t have trouble accessing them – for instance heavily overloaded .Net methods in IronPython can be a recipe for frustration later on, same goes with using multiple out or ref parameters – that’s not to say IronPython can’t access them, just that it’s awkward and unpleasant (something your scripting language should not be). Second to this is security – dynamic languages effectively introduce a surface area to your application that didn’t exist before – our server allows configuration (including iron python scripts) to be applied via a web service – you want to make absolutely sure there is sufficient trust between endpoints, and don’t repeat mistakes of the past with other scripting languages (think injection attacks).
 Sunday, February 18, 2007
It seemed a long time coming, but finally Rhino Mock's 3.0 is available, which of course also means Dynamic Proxy 2 has made it to that sweet generic method support nirvana as well :) I don't know where I'd be without these tools, I haven't done a .Net project without them in the last couple of years... in fact it's fueled my reluctance over the last couple of years for returning to bespoke development at any NZ dev shop which might dictate other (crappier) alternatives ;o) I also noticed that mono is getting it's C# 3.0 support slowly sorted... Extension methods are in, as is some Lambda support... I need to sit down and spend some time thinking about how I should go about unit testing some of this stuff, it's on my list of "testing" things to do right after getting to grips with RhinoMocks 3 and perhaps writing another blog entry on mocking Base4 with all the new "goodies" - I need to do a monorail/base4 website for another little venture, so it's probably as good a time as any. Went for a swim at Omaha today... just can't get enough of the beach this year - John Campbell turned up at the same time we did, there's only so many "Not in front of John" jokes I can handle in one day... or a life time ;o)
 Tuesday, February 13, 2007
Found myself writing a simple class for implanting "trial" logic for a client (as in you have 30 days left of your trial etc.) ... it relies on the current date and time, and so you can never really be assured your tests are robust unless you can control the current date & time within the test fixture (in fact any time you find yourself writing DateTime.Now alarm bells should be going off... even worse is logic based on DateTime.Now where it's evaluated more the once for a single function). In the past I've generally Implemented something like an "IClock" interface, which would have a method like "DateTime GetCurrentTime()" or whatever seemed appropriate to the situation... but I decided to go with the lightweight solution of delegates instead in the morning, if only because I was being lazy I didn't see the need for creating an entire interface for such a trivial requirement... so we have:
private DateTime _trialExpirey;
private int _maxExecutions;
private TimeSpan _trialDuration;
private Func<DateTime> _nowFunction;
public TrialUpdater(DateTime trialExpirey, int maxExecutions, TimeSpan trialDuration)
: this(delegate { return DateTime.Now; }, trialExpirey, maxExecutions, trialDuration)
{
}
public TrialUpdater(Func<DateTime> nowFunction, DateTime trialExpirey, int maxExecutions, TimeSpan trialDuration)
{
if (nowFunction == null) throw new ArgumentNullException("nowFunction");
_nowFunction = nowFunction;
_trialExpirey = trialExpirey;
_maxExecutions = maxExecutions;
_trialDuration = trialDuration;
}
But I'm starting to wonder if this code doesn't smell a bit if I start using it other places... for instance: - Could I supply an alternative delegate via the castle container...?
- Could I mock out the nowFunction parameter easily using something like RhinoMocks and still have it participate in constraints...?
I'm thinking in the case of mocking it out you would probably need to implement some interfaces which lines up with the generic delegates (Func<Ret,T1,T2...> and Proc<T1,T2...> etc.) - so I would end mocking out an IFuncEvaluator<Ret> interface (or in this case IFuncEvaluator<DateTime>) -which would implement a method "T Evaluate();"... and the pass an anonymous delegate which in turn invokes the mocked IFuncEvaluator<Ret>. Though maybe I've missed something and mocking out delegates is doable with the current RhinoMocks..? As for being able to inject a value for the nowFunction parameter, I'm thinking a nice solution would be to actually wire it up to a method on another service declaratively i.e.
<component id="trialUpdater" type="MyLib.TrialUpdater, MyLib" >
<parameters>
<nowFunction>
<method service="clockService" method="GetCurrentTime" />
</nowFunction>
</parameters>
</component>
Which I believe should be doable using a facility and a type converter... but I'm sure the devil's in the detail :) At any rate, just a minor distraction, back to work. As an aside the clocks a pretty boring example, but there are times when you want to manipulate the time for instance: - If you want to manipulate the time (return dates as UTC instead of Local)
- Clamp the current Time so it's limited to a certain level of accuracy... perhaps you have an external expectation that all dates will be recorded at a 10ms level of accuracy (perhaps you want to align database timestamps with timestamps within your application).
- Perhaps your application uses the clock to work with snapshots of your domain model in the past.
How many people are actually using anonymous delegates and generic Func<T...> / Proc<T...>'s in their day to day coding for tasks like this?
 Tuesday, February 06, 2007
Just a quick post, for part two let's look at grouping our results for display purposes... first off, I grab only the episodes which we think are "valid" (in this case ones which are assigned a series, episode and part number)...
EpisodeParser episodeParser = new EpisodeParser();
YouTubeSearcher searcher = new YouTubeSearcher(DeveloperId);
// get a list of all the parts we are interested in
IEnumerable<EpisodePart> parts = (from result in searcher.QueryByTags("QI", "Quite", "Interesting")
select episodeParser.Parse(result))
.Where(p => p.SeriesNumber > 0 && p.EpisodeNumber > 0 && p.PartNumber > 0)
.Distinct();
Obviously what I've done here is probably rather poor style, surely the where clause could have been inside the select statement??... but I'm just trying to illustrate how you can mix the two notations... next we're going to group the results up using some nested "group by" and object projections... this is disgustingly easy, what more can you say about it.
// group those parts
var allSeries = from part in parts
group part by part.SeriesNumber into series
orderby series.Key
select new { SeriesNumber = series.Key,
Episodes = from episodePart in series
group episodePart by episodePart.EpisodeNumber into episodes
orderby episodes.Key
select new {EpisodeNumber = episodes.Key,
Parts = from chunk in episodes
orderby chunk.PartNumber
select chunk
}
};
Great, I think that saved us a lot of time, compared to doing it ourselves in C# 2.0... let's now generate a little page to view the results - for now I'm just writing code in NUnit fixtures - so we'll use Console.WriteLine... though in a website I would probably just use some quite similar brail template code.
foreach (var series in allSeries)
{
Console.WriteLine("<h3>Series {0}</h3>\r\n", series.SeriesNumber);
foreach (var episode in series.Episodes)
{
Console.WriteLine("<h4>Episode {0}</h4>\r\n", episode.EpisodeNumber);
foreach (var author in episode.Parts.GroupBy(p => p.Result.Author))
{
Console.WriteLine("<div>Author: <strong>{0}</strong>\r\n", author.Key);
foreach(var part in author)
{
YouTubeResult result = part.Result;
Console.WriteLine("<a href=\"{0}\">part {1} <img src=\"{2}\" /></a>", result.Url, part.PartNumber, result.ThumbUrl);
}
}
}
}
I've also dumped the output from this to an html page, if you'd like to have a look at it. Next time I might have a look at storing the results of the youtube query with base4 and writing some code for a little daemon which can identify newly posted episode parts on a periodic basis... which should all lead towards implementing the RSS feed capability I discussed in part one. But for now I'm off to enjoy the sun!
 Friday, February 02, 2007
Well, the recent musings of Alex James have caught my interest around LINQ (part one and two) - and so I thought I would start having a play with LINQ and using it to query some well known web sites... and decided to go with dragging some info out of youtube... Basically, I like QI (also known as Quite Interesting - british comedy show) - and there's a lot of episodes on youtube, querying on the tags "QI", "Quite" & "Interesting" returns about 1000 results... almost every result represents a part of an episode... and most people posting are kind enough to include something in the title or description of the video which lets you know which episode and series it belongs to... However it's going to take some effort to actually start watching at series 1, episode 1 and work your way through the episodes in the right order by endlessly browsing youtube's search results... unless we start "value adding" - creating an "episodic" view over youtube's data. At this point you could put your magic hat on and wish for features from you're youtube "episodes" site: - Perhaps an RSS feed notifying me of new episodes as they're listed on youtube daily.
- A nice way to see a series, it's episodes, and each part that I need to play.
- Maybe some aggregation of episode summaries from another web site for each episode (in this case I'm thinking maybe TVRage.Com...)
So you can quickly see that we can start making something virtually out of nothing, like MacGyver... but much lamer and without the hair. First things first, I started having a look at YouTube's API - you can search by tags and get plenty of info back from their REST web service, but you can only get 20 results per page, 20 results isn't much cop so I built a simple class which gives access to the whole set of search results as an IEnumerable<YouTubeResult > - here's the code for that:
public class YouTubeSearcher
{
private const string TagQuery = "http://www.youtube.com/api2_rest?method=youtube.videos.list_by_tag&dev_id={0}&tag={1}&page={2}";
private string _developerId;
public YouTubeSearcher(string developerId)
{
if (string.IsNullOrEmpty(developerId)) throw new ArgumentNullException("developerId");
_developerId = developerId;
}
public IEnumerable<YouTubeResult> QueryByTags(params string[] tags)
{
if ((tags == null) || (tags.Length <= 0)) throw new ArgumentNullException("tags", "tags must contain one or more tags");
for (int page=1; true; page++)
{
List<YouTubeResult> results = QueryByTagAndPage(JoinTags(tags), page);
if (results.Count <= 0) break;
foreach (YouTubeResult result in results) yield return result;
}
}
private string JoinTags(string[] tags)
{
if (tags.Length == 1) return tags[0];
StringBuilder builder = new StringBuilder(tags[0]);
for (int i=1; i<tags.Length; i++) builder.AppendFormat(",{0}", tags[i]);
return builder.ToString();
}
private List<YouTubeResult> QueryByTagAndPage(string tag, int page)
{
Console.WriteLine("Querying by tag: {0}, page: {1}", tag, page);
Stopwatch watch = Stopwatch.StartNew();
try
{
List<YouTubeResult> results = new List<YouTubeResult>();
string uri = string.Format(TagQuery, _developerId, tag, page);
XPathDocument xpd = new XPathDocument(uri);
XPathNavigator xpn = xpd.CreateNavigator();
XPathNodeIterator xniError = xpn.Select(@"/ut_response");
xniError.MoveNext();
if (xniError.Current.GetAttribute("status", String.Empty) == "fail")
{
string expression = "/ut_response/error/description";
string errorText = xpn.SelectSingleNode(expression).InnerXml;
throw new YouTubeException("Error occured while querying youtube: {0}", errorText);
}
try
{
XPathNodeIterator xni =
xpn.Select(@"/ut_response/video_list/video");
while (xni.MoveNext())
{
XPathNavigator navigator = xni.Current;
string title = navigator.SelectSingleNode("title").InnerXml;
string url = navigator.SelectSingleNode("url").InnerXml;
string thumbUrl = navigator.SelectSingleNode("thumbnail_url").InnerXml;
string id = navigator.SelectSingleNode("id").InnerXml;
string description = navigator.SelectSingleNode("description").InnerXml;
int lengthInSeconds = int.Parse(navigator.SelectSingleNode("length_seconds").InnerXml);
string author = navigator.SelectSingleNode("author").InnerXml;
results.Add(new YouTubeResult(id, url, title, thumbUrl, lengthInSeconds, description, author));
}
}
catch (XPathException xpe)
{
throw new YouTubeException("Xpath exception occured: {0}", xpe.Message);
}
return results;
}
finally
{
Console.WriteLine("Query complete in {0}ms", watch.ElapsedMilliseconds);
}
}
}
Following on from that we need to parse each search result and attempt to pull out it's episode information: - Series Number
- Episode Number
- Part Number
At this point we might also make the assumption that parts should be grouped by the user who posted them - in case the same episode has been posted twice by two users (quite likely, people are silly). Parsing part information could be done using successive LINQ queries, but It's actually not that pleasant considering we're generally interogating only two text fields - the title for the clip, and it's description - horses for courses - so instead I built a quick 'n dirty " EpisodeParser" class... here's the code for that:
public class EpisodeParser
{
private List<AbstractContributor> _contributors = new List<AbstractContributor>();
public EpisodeParser()
: this(
new SeriesContributor(),
new EpisodeContributor(),
new PartContributor(),
new XFormatContributor(),
new PilotContributor(),
new PartOfPartsContributor(),
new WordNumberPartsContributor())
{
}
public EpisodeParser(params AbstractContributor[] contributors)
{
if (contributors != null) _contributors.AddRange(contributors);
}
public EpisodePart Parse(YouTubeResult result)
{
EpisodePart ep = new EpisodePart(result);
foreach (AbstractContributor contributor in _contributors)
{
contributor.Contribute(ep);
}
return ep;
/*
* QI Series 4 EpisodePart 12 (part 3)
* s2e10 part 1/4
* Qi Series 1 Ep 5 Part 1/3
* QI 2x01
* Take Out 1
* QI Pilot EpisodePart part 6
* S2E09
*/
}
private class SeriesContributor : AbstractContributor
{
public override void Contribute(EpisodePart episodePart)
{
int? seriesNumber = ParseNameNumber(episodePart, "series", "s");
AssignSeriesNumber(episodePart, seriesNumber);
}
}
private class EpisodeContributor : AbstractContributor
{
public override void Contribute(EpisodePart episodePart)
{
int? episodeNumber = ParseNameNumber(episodePart, "episode", "ep", "e");
AssignEpisodeNumber(episodePart, episodeNumber);
}
}
private class PartContributor : AbstractContributor
{
public override void Contribute(EpisodePart episodePart)
{
int? partNumber = ParseNameNumber(episodePart, "part", "p");
AssignPartNumber(episodePart, partNumber);
}
}
private class PilotContributor : AbstractContributor
{
public override void Contribute(EpisodePart episodePart)
{
if (episodePart.Result.Title.ToUpper().Contains("PILOT"))
{
AssignSeriesNumber(episodePart, 1);
AssignEpisodeNumber(episodePart, 1);
}
}
}
private class XFormatContributor : AbstractContributor
{
public override void Contribute(EpisodePart episodePart)
{
int seriesNumber = 0;
int episodeNumber = 0;
if (SplitNumber(episodePart, ref seriesNumber, ref episodeNumber, 'X'))
{
AssignSeriesNumber(episodePart, seriesNumber);
AssignEpisodeNumber(episodePart, episodeNumber);
}
}
}
private class PartOfPartsContributor : AbstractContributor
{
public override void Contribute(EpisodePart episodePart)
{
int partOf = 0;
int parts = 0;
if (SplitNumber(episodePart, ref partOf, ref parts, '/'))
{
AssignPartNumber(episodePart, partOf);
}
}
}
private class WordNumberPartsContributor : AbstractContributor
{
private static readonly Dictionary<string, int> _phrases;
static WordNumberPartsContributor()
{
_phrases = new Dictionary<string, int>();
_phrases.Add("part one", 1);
_phrases.Add("part two", 1);
_phrases.Add("part three", 1);
_phrases.Add("part four", 1);
_phrases.Add("part five", 1);
_phrases.Add("part six", 1);
_phrases.Add("part seven", 1);
_phrases.Add("part eight", 1);
_phrases.Add("part nine", 1);
_phrases.Add("part ten", 1);
}
public override void Contribute(EpisodePart episodePart)
{
AssignPartNumber(episodePart, FindPhrase(episodePart, _phrases));
}
}
}
At this point we have the building blocks for starting to write some LINQ queries... here's my first test - running a basic "select all"...
YouTubeSearcher searcher = new YouTubeSearcher(DeveloperId);
IEnumerable<YouTubeResult> results = from result
in searcher.QueryByTags("QI", "Quite", "Interesting")
select result;
Console.WriteLine("total results: {0}", results.Count());
Trying a more explicit style of query, and parsing episodes:
EpisodeParser episodeParser = new EpisodeParser();
YouTubeSearcher searcher = new YouTubeSearcher(DeveloperId);
IEnumerable<EpisodePart> parts = searcher.QueryByTags("QI", "Quite", "Interesting")
.Select(result => episodeParser.Parse(result))
.Where(part => part.SeriesNumber == 1 && part.PartNumber == 1)
.OrderBy(part => part.EpisodeNumber);
foreach (EpisodePart part in parts.Distinct())
{
Console.WriteLine(part);
}
Which will let us know which episodes in series 1 exist... Bit of a rush, but next time I'll start digging in a little deeper... At this point though it's worth noting that we have some stuff for free because of IEnumerable<T >... - Search results are being processed as their yielded, if we're just looking for the first matching item for a query we can stop without having to request additional result pages on a match is made.
- Same goes for episodes, we only parse them as they are required - no unnecessary overhead.
So far nothing has required LINQ, but I think we'll start to see it being a great time saver come the next couple of parts... compared to writing the code ourselves. We shall see!
 Thursday, November 30, 2006
The evil designer attribute ;o)
I'm working on a project at the moment where the client want's an "Add-in" for an existing piece of software... it's a COM interop project, .Net 2.0 (and yes, it uses Castle, IoC sits in nicely with the IServiceProvider :) and it hosts a custom designer, and the add-ins must exist in their own directory, outside of the host applications base directory.
At any rate, it's been working just fine so far, but today I was trying to introduce some custom designers... and they weren't being constructed... which highlighted some odd behaviour in the design time support - I have 6 or so assemblies, most are support assemblies, some containing controls and their associated designers, something like this:
public class MyButtonDesigner : ControlDesigner { ..}
[Designer(typeof(MyButtonDesigner))] public class MyCustomButton : ButtonBase { .. }
And then there is the core assembly which hosts the design surface etc. and contains a number of COM-visible classes - one of these class in the core assembly is constructed via Com interop by it's Name, and everything starts it's life from there in their Add-in, much like a Main class in a WinForms project.
So the core assembly references the support assemblies, and has no problem creating controls at runtime within these assemblies...
But then...
However, the design time support fails to construct or make use of the custom designers... and doesn't blow up, it just fails silently - personally I hate this kind of behaviour... I like things to fail fast, in your face :)
It appears the custom designer is never constructed because the design time infrastructure fails to locate the assembly it's held within, even though my code has just created an instance of a control from the same said assembly not an instant before... arghh!
To my mind this is madness... I'm not passing a string reference to the type, and the assembly is already loaded, it should be as simple as using the Type in the attribute to create an instance of the designer - looking at the internal implementation of this attribute, I can see where it all goes terribly wrong:
public DesignerAttribute(Type designerType) { this.designerTypeName = designerType.AssemblyQualifiedName; this.designerBaseTypeName = typeof(IDesigner).FullName; }
It's still a puzzle as to why this isn't being resolved... the assembly is already loaded against the current AppDomain - I guess I could mess with the fusion logger to figure it out, there must be some subtle different - but I didn't have the time to waste, so I just cheated, implementing an AppDomain.AssemblyResolve event handler to take care of returning the assembly that's already loaded when matching against a set of pre-loaded assemblies.
I think the silent failure is what annoys me the most, this is something which could be easily introduced and might not be imediately detected when performing a minor update... I'm still not sure how I could write a test to detect it...
Speaking of custom designers... I'm unimpressed by how most custom designers are marked internal... especially for classes that are designed to be subclassed... why the hell is the ButtonBaseDesigner marked internal?
 Tuesday, November 14, 2006
More mocking...
The title for this entry should probably be "more IRepository<T> mocking" - as that's what I'm mocking out... but at any rate, let's get down and dirty... In this entry I will cover mocking out a "complex" method, incidentally I think the size of this test suggests that our test isn't fine grained enough (and that individual features within the data loader should be exposed so we can test them better) - but that's my problem, not yours ;o)
Background
So, as some background, this is a test for a class called "DataLoader" - a most unimaginative name for a class that loads data... it's used for loading an XML file which has a bunch of info for different entities... if your recall the last entry, I was talking about simplistic music information, well this class can be used to load musical data into the store, including something not mentioned so far, which is the "test suite" - the test suite defines tests which can be run against the music in the store, the details aren't really up for discussion, but it's for executing customer acceptance tests, not unit tests.
The test below checks one of the primary paths, where by no pre-existing data is available, so it must all be created by the data loader first, before creating the customer acceptance test, which references the track, release etc. data (the definition for customer acceptance test suites are also stored in the store, as are the results from run the customer acceptance tests).
Diving In...
So here is the test for loading a "test suite" for a single track, the song "Dirty Harry" by the "Gorillaz", we are testing the behavior of loading the file when the track, release and artist do not already exist in the store - most of this is basic RhinoMock's usage (though I'm no expert, I'm probably misusing some of the features...).
[Test]
public void LoadDataFreshForSingleTrack()
{
/**** RECORD ****/
Environment environment = new Environment();
SourceDevice sourceDevice = new SourceDevice();
RecordingDevice recordingDevice = new RecordingDevice();
Track track = new Track();
ObjectPath artistPath = (Artist.Fields.Name == "Gorillaz");
Expect.Call(_artistRepository.FindOne(artistPath)).Constraints(Base4Query.PathEqual(artistPath)).Return(null);
_artistRepository.Save(null);
LastCall.Constraints(Property.Value("Name", "Gorillaz"));
ObjectPath releasePath = (Release.Fields.Name == "Demon Days");
Expect.Call(_releaseRepository.FindOne(releasePath)).Constraints(Base4Query.PathEqual(releasePath)).Return(null);
_releaseRepository.Save(null);
LastCall.Constraints(Property.Value("Name", "Demon Days") &&
Property.ValueConstraint("Artist", Property.Value("Name", "Gorillaz")));
_trackRepository.Save(null);
LastCall.Constraints(Property.Value("Name", "Dirty Harry") &&
Property.ValueConstraint("Release", Property.Value("Name", "Demon Days")));
ObjectPath encodingPath = (TrackContentEncoding.Fields.Name == "MP3");
Expect.Call(_encodingRepository.FindOne(encodingPath)).Constraints(Base4Query.PathEqual(encodingPath)).
Return(null);
_trackContentRepository.Save(null);
LastCall.Constraints(Property.ValueConstraint("Track", Property.Value("Name", "Dirty Harry")));
ObjectPath trackReferencePath = (Track.Fields.Name == "Dirty Harry" &&
Track.Fields.Release.Name == "Demon Days" &&
Track.Fields.Release.Artist.Name == "Gorillaz");
Expect.Call(_trackRepository.FindOne(trackReferencePath)).Constraints(
Base4Query.PathEqual(trackReferencePath)).Return(track);
Expect.Call(_trackRepository.FindOne(trackReferencePath)).Constraints(
Base4Query.PathEqual(trackReferencePath)).Return(track);
ObjectPath environmentPath = (Environment.Fields.Name == "Indoors");
Expect.Call(_environmentRepository.FindOne(environmentPath)).Constraints(
Base4Query.PathEqual(environmentPath)).Return(environment);
ObjectPath sourceDevicePath = (SourceDevice.Fields.Name == "Loopback");
Expect.Call(_sourceDeviceRepository.FindOne(sourceDevicePath)).Constraints(
Base4Query.PathEqual(sourceDevicePath)).Return(sourceDevice);
ObjectPath recordingDevicePath = (SourceDevice.Fields.Name == "Loopback");
Expect.Call(_recordingDeviceRepository.FindOne(recordingDevicePath)).Constraints(
Base4Query.PathEqual(recordingDevicePath)).Return(recordingDevice);
_testSuiteRepository.Save(null);
LastCall.Constraints(Property.Value("Name", "One track, one loopback sample") &&
Property.Value("Description",
"Testing with 30 second snippets pulled from the source files with audacity (Loopback)") &&
Property.ValueConstraint("Tracks",
ItemListOf<Track>.NumberOfItems(1) && ItemListOf<Track>.IndexedItemConstraint(0, Is.Same(track))));
/***** REPLAY *****/
_mockRepository.ReplayAll();
DataLoader loader = CreateLoader();
loader.LoadData(OneTrackFile, ContentPath);
_mockRepository.VerifyAll();
}
First you'll probably see that the callback and anonymous delegates from the last post are absent, they've been replaced with constraints... which has made the syntax a lot more concise - so far the rhino mocks support is pretty basic, we have two static classes being used for creating the constraints:
- Base4Query - for constraints on ObjectQuery and ObjectPath arguments/properties.
- ItemListOf<T> - for constraints on IItemList<T> arguments/properties.
The constraints method in RhinoMocks expects the same number of arguments as the associated method call on the mock object, constraints work on the arguments value, however you can apply constraints to the value of single property of an argument, and those constraints can be logically AND or OR'd together - for instance here:
_testSuiteRepository.Save( null);
LastCall.Constraints(Property.Value("Name", "One track, one loopback sample") &&
Property.Value("Description",
"Testing with 30 second snippets pulled from the source files with audacity (Loopback)") &&
Property.ValueConstraint("Tracks",
ItemListOf<Track>.NumberOfItems(1) && ItemListOf<Track>.IndexedItemConstraint(0, Is.Same(track))));
We are applying these constraints:
- The first argument should:
- Have a property called "Name", and it's value should be "One track, one loopback sample".
- And have a property called "Description", and it's value should be "Testing...." etc.
- And have a property called "Tracks", which is of type IItemList<Track> which:
- Contains a total of 1 items
- And the item at index 0 should:
- Be the same as the instance returned from an earlier save call.
Notice that we have to call the method we want to apply constraints to first, so that we can address it with LastCall - a necessary evil when the method has a return type of void... otherwise you can use the more pleasant "Expect.Call(...)" convention.
Also, I'm declaring instances of the expected Base4 object paths, and then applying them in the constraints... I could in-line the object paths, but I then need to disambiguate the overloaded call to the FindOne method, so we have my preference:
ObjectPath trackReferencePath = (Track.Fields.Name == "Dirty Harry" &&
Track.Fields.Release.Name == "Demon Days" &&
Track.Fields.Release.Artist.Name == "Gorillaz");
Expect.Call(_trackRepository.FindOne(trackReferencePath)).Constraints(
Base4Query.PathEqual(trackReferencePath)).Return(track);
or this:
Expect.Call(_trackRepository.FindOne(( ObjectPath) null)).Constraints(
Base4Query.PathEqual(Track.Fields.Name == "Dirty Harry" &&
Track.Fields.Release.Name == "Demon Days" &&
Track.Fields.Release.Artist.Name == "Gorillaz")).Return(track);
The second involves less code, but I think it's easy to get confused between the compile time query language's logical operators and those of the RhinoMock's constraints... each have merits of course.
Conclusion...
I'm still working through some of the finer points of the implementation (and so won't publish any code just yet...) but this should give you some ideas about how you can test base4 interactions in your application with RhinoMocks, instead of hitting the base4 server and testing the results... and I think it's a lot more intuitive when attempting to do TDD with base4...
I would also like to make a special mention that this code won't actually work with the latest published release of Base4... there is an issue preventing the addition of items to an IItemList<T> in some situations when you have not set a valid default context - there is a fix (Which works well) in the Base4 trunk, and I assume Alex James will release this at some point... and thanks for resolving that issue so quickly Alex :) much appreciated.
 Saturday, November 11, 2006
Domain Driven Design Afterthoughts...
I just finished reading Jimmy Nilsson’s Applying Domain-Driven Design and Patterns [ADDDP] book... I actually read it cover to cover, something I’ve found difficult to compel myself to do with some of the other books that have been lying around my desk for a wee while now (such as Petzold’s “Applications = Code + Markup” – a great book to assault someone with in a dark alley)...
First off, I think this book is a pretty good, it didn’t cover a lot of new ground for me, but It’s very down to earth, which I liked, and it’s encouraged me to have a read of Evan’s and Fowler’s more definitive works on the subject too... I also liked the fact that this book does attempt to tie the whole story together, from rough sketch through to identifying the domains language, using TDD to build up your domain model and even some of the gritty integration work, including evaluating OR/M features, using NHibernate as an example, and even looks into inversion of control contains (spring sadly, it would’ve been great to have seen Castle get a mention) and finally AOP. On the down side – I think the book could’ve tackled the application of rules to your domain model a little better (I wanted to see more code) and depending on your TDD knowledge, you might find that a couple of the chapters don’t really do much for you as there’s little focus on the model so much as the key concepts of red, green, refactor...
At any rate, one thing I did keep rolling around in the back of my mind is just how Base4.Net fits into the “domain model” picture ... it’s difficult to nail down, there are plenty of mechanisms for implementing most of what you need to create a domain model, for instance:
- Inheritance, though it’s support for discriminators in user types isn’t quite up to scratch – it only works via “ItemBase” at the moment – though I think Alex James mentioned that this would be implemented at some point... and though I haven’t tried, you could roll your own in some way.
- Aggregates (through extended properties).
- Various hooks (Events) to allow for the application of custom behavior, for instance you could wire up to a BeforeSave event on a type and implement some custom validation rules... not that easy to test though .
- A reasonable query abstraction - Good query support.
- A “logical” transaction mechanism, suitable for supporting the concept of a “UnitOfWork”, though it’s explicit, rather the implicit, and based on the examples in the documentation this could be a little annoying to work with when you’re trying to persist the entire graph for an aggregate – however using a similar implementation for “UnitOfWork” as Ayende does in the Rhino.Commons library for NHibernate I’m sure I could get it all working nicely, without too much trouble.
And it sounds like I’m on to a winner... but I think what I struggle with is that the types in your schema are not really the focal point for your domain model, because they’re not POCO, unlike say a domain model implemented with NHibernate as the backing O/RM can be, you can’t enrich or decorate them with additional functionality all that easily... It’s not that you have to build your domain model this way, it’s just that’s the way I would like to do it, at least to satisfy me that I'm not being railroaded into a bad design choice – but I think it’s the small blood price you pay for letting Base4 generate the schema assemblies for you, that loss of control is also a boon in immediate productivity when you start developing apps with Base4 apps... I’ve come close while using ActiveRecord, but it’s still not the same.
So... given the restrictions I’m left to implementing additional abstractions for my domain model... which means using repositories and services for encapsulating the business logic... which, in turn, brings me to mocking...
Mocking out my Base4 Implementation...
Now, if you recall a while back I talked about my repository implementation... basically it let you do things like:
IRepository<Order> orderRepository = IoC.Resolve<IRepository<Order>>();
Order orderForApples = new Order();
OrderLine greenOnes = new OrderLine();
OrderLine redOnes = new OrderLine();
orderForApples.OrderLines.Add(greenOnes);
orderForApples.OrderLines.Add(redOnes);
orderRepository.Save(orderForApples);
Big woop, but what I probably neglected to mention is that the repository is great for implementing a chain of generic decorators (which can be set up in your IoC container of course)... so at the bottom/base of the chain we may have our “Base4StorageRepository” and layered on top of that we might have various decorators (each injected with a dependency for the next repository in the chain) for implementing some useful concepts...
Things that spring to mind are:
- Security
- Validation
- Logging
Being able to configure these things is quite useful, and there’s little stopping you deploying additional decorators as additional assemblies for an already installed product – just throw in some additional container configuration - and it is a great deal more elegant then implementing this functionality with AOP.
But you do kind of paint yourself in a corner at the same time... this generic decorator pattern stops you from being able to decorate the repository with additional methods for implementing business level functionality (because any decorations that are applied to your base repositorty will mask out methods and properties no present in the IRepository<T> interface)... that’s fine though, I guess we just have to write the repository off as being more of a persistence mechanism, It’s really a logical separation of concerns anyway... you can decorate a "wrapper" at the top of the chain though (and this is how Ayende does, but lets ignore that for now ;o)
So... A higher level entity for dealing with the business level concerns is required... I call mine services, that may or may not sit right with you, but it makes reasonable sense in my application – and these service are injected as dependencies of the controllers re: MVC, yeah this is a Monorail app (or at least, part of it is)...
These services often aggregate the features of multiple repositories, like this catalogue service below which deals with a simple music structure:
public class CatalogueService : ICatalogueService
{
public CatalogueService(IRepository<Track> trackRepository, IRepository<Release> releaseRepository,
IRepository<Artist> artistRepository, IRepository<Genre> genreRepository)
{
if (trackRepository == null) throw new ArgumentNullException("trackRepository");
if (releaseRepository == null) throw new ArgumentNullException("releaseRepository");
if (artistRepository == null) throw new ArgumentNullException("artistRepository");
if (genreRepository == null) throw new ArgumentNullException("genreRepository");
_trackRepository = trackRepository;
_releaseRepository = releaseRepository;
_artistRepository = artistRepository;
_genreRepository = genreRepository;
}
In this case we have a dependency on four different repositories...
For this example we have a pretty simple schema... with a child-parent relationship between Track, Release and Artist... and a Many to Many relationship between Tracks and Genres...
Track -> Release -> Artist Track(s) <-> Genre(s)
The catalogue service implements the business rules for dealing with the catalogue, in some cases this is no more than querying the associated repository... so for getting a list of releases for a particular artist we have this (and yeah, I know it’s pretty daft):
public PagedItemList<Track> ListTracksForArtist(Artist artist, int pageSize, int pageNumber)
{
ObjectQuery query = new ObjectQuery(typeof (Track));
query.Scope.Add("Release");
query.Scope.Add("Release.Artist");
query.Path = (Track.Fields.Release.Artist.ID == artist.ID);
query.Path.AddOrderBy("Name", OrderByDirection.Ascending);
return _trackRepository.Find(query, pageSize, pageNumber);
}
I say daft because it doesn’t support sorting and filtering by a query... but it’s here to illustrate a point, and until the customer actually asks for these features I’m not going to bother building them :P
At any rate, the point is not to critique the service, but instead how can we test this catalogue service without being connected to a Base4 server... and of course it’s RhinoMocks to the rescue!
Mocking with RhinoMocks...
So here’s the guts of the test in mid-refactoring ... post red-green for those sticklers for the rules ;o) (there’s still plenty yet to clean up, but it would muddy the waters a bit for this example I think...)
[ Test]
public void ListReleasesForArtist()
{
Artist artist = new Artist();
PagedItemList<Release> releases = new PagedItemList<Release>(new ItemList<Release>(), 1, 10, 20);
Func<bool, ObjectQuery, int, int> callback
= delegate(ObjectQuery query, int pageNumber, int pageSize)
{
ObjectPath path = Release.Fields.Artist.ID == artist.ID;
path.AddOrderBy("Name");
Base4Assert.ArePathsEqual(path, query.Path);
Base4Assert.AreScopesEqual(new string[] { "Artist" }, query.Scope);
Assert.AreEqual(1, pageNumber, "pageNumber");
Assert.AreEqual(10, pageSize, "pageSize");
return true;
};
Expect.Call(_releaseRepository.Find(null, 1, 10)).Callback(callback).Return(releases);
_mockRepository.ReplayAll();
ICatalogueService service =
new CatalogueService(_trackRepository, _releaseRepository, _artistRepository, _genreRepository);
PagedItemList<Release> results = service.ListReleasesForArtist(artist, 1, 10);
Assert.AreSame(releases, results);
_mockRepository.VerifyAll();
}
Pretty chunky I know - but as more tests are added there will be opportunities for removing some of that duplicated effort... however the key points to take away are:
- We don’t need to have the base4 service running.
- We are actually testing the catalogue service’s interactions with the repositories, instead of relying on detecting expected side effects in the underlying storage.
- We’re verifying the object path and scope for the query, as well as paging information, and insulating ourselves from difficult to detect changes (like forgetting to apply an object scope, which may have a severe impact on performance).
Just to complete the story, the mock repository was created in the Setup (as we use it for every test case)... here's the code for it:
[ SetUp]
public void SetUp()
{
_mockRepository = new MockRepository();
_trackRepository = _mockRepository.CreateMock<IRepository<Track>>();
_releaseRepository = _mockRepository.CreateMock<IRepository<Release>>();
_artistRepository = _mockRepository.CreateMock<IRepository<Artist>>();
_genreRepository = _mockRepository.CreateMock<IRepository<Genre>>();
}
It doesn’t stop us from incorrectly spelling an object scope I think compile time query support for ordering and scoping of an object query will help to make this a little more robust... small potatoes.
The callback in this case is a bit of a “bad smell” – there’s support in rhino mocks for parameter constraints, but the object paths and scopes are a little too complex to test using the out the box ones... though you can get surprisingly close, they are pretty powerful... but I believe you can write custom constraints yourself – which is something I’ll do for the next post (I’ve never done it before, I'm guessing it's easy) and hopefully that will reduce the complexity of these tests quite a bit, and replace the less concise anonymous delegate, and more importantly, make it easy to develop the catalogue service in a test-driven manor.
For those more observant people you may have noticed the “Base4Assert” as well – that’s a little static helper class I’m using in these tests... it’s not perfect, but it works for simple cases including things like multi-level scopes and gives meaningful failure methods like “expected scope ‘Release.Artist’ but found nothing.” Or "expected OrderBy Name Descending, but found OrderBy Name Ascending"... which can quickly narrow down problems for you, especially if your writing these tests first (which is the whole point of this exercise I feel).
Conclusion... For Now ;o)
Last thing I’ve done is to have tossed away a lot of the additional query overloads in my original repository design in favor of just using a single ObjectQuery parameter with and without page number and page size (returning a PagedItemList<T> when providing a page number and page size, and returning an IItemList<T> when querying without them) – It makes everything a lot more... predictable, and is a lot cleaner when you start considering generic decorator implementations (10 overloads is 10 more code paths that need testing in a decorator... ) - looking towards to the future it should conceivable that a compile time query will allow you to construct the entire object query, not just the unordered path, and I’m quite happy to build these up in a few lines of code before passing them to a find method for now.
Edit (Sunday 12th):
In a similar vein, I just noticed Ayende's great MSDN article this evening - which covers that whole IRepository<T> story, including generic decorators and most importantly the intricacies of registering and chaining these components in the windsor container... great stuff!
 Wednesday, November 08, 2006
Nothing particularly interesting to report, while I'm sitting here watching a custom-built automated test suite chug away (which incidentally takes approximately 5 hours to run... at 100% CPU usage on 1 core... ugh) - I thought I'd muck around with Iron python and base4... my inspiration was this "On the fly" schema creation on the base4 site, however I wanted to just grab an existing assembly (from the server no less) and start using it's types in Iron Python... it's pretty easy (and quite cool, think about the implications of no references, every time you run your app the schema might have magically grown some more features ;o)
Getting Started...
First off, lets fire up the trusty iron python console... I like colours and being able to tab through member lists, so I'm going to throw in some command line parameters...
ipy -X:TabCompletion -X:ColorfulConsole
Cool, consoles up and running so lets get down to business... first things first, loading up the Base4.Storage assembly...
import sys
import clr
sys.path.Add("C:\\Program Files\\Base4 Solutions Ltd\\Base4 version 2.1.1.85")
clr.AddReferenceToFile("Base4.Storage.dll")
from Base4.Storage import *
All done... now before we can do anything useful, we'll need to setup our default connection string (read: default context)...
StorageContext.SetDefault("tcp://Server:@localhost:999/Base4_default")
This is the amiga speaking...
Now the fun begins... if you have System.Speech available, grab that puppy too... because deep down we all know that the thrill of making your computer talk still exists... especially if you started out your days on an Apple or better yet Amiga...
clr.AddReference("System.Speech")
from System.Speech.Synthesis import *
synth = SpeechSynthesizer()
Sweet, now lets view (or listen) for all the available schema assemblies...
for asmFile in StorageContext.FindAll[SchemaAssemblyFile]():
synth.SpeakAsync(asmFile.Name)
print asmFile.Name
Loading the schema...
At this point you'll end up with a list of the assembly files (and hopefully, your machine will be droning away notifying of you just what they're called... ;o) in my case I have a little "Experiment.dll", so lets load that up... I'm pressed for time so I won't be putting in speech detection for selecting the appropriate schema, though it's both entirely possible, and pretty easy to do...
asmFile = StorageContext.FindOne[SchemaAssemblyFile]("Name='Experiment.dll'","")
assembly = experimentAssembly.LoadAssembly()
clr.AddReference(assembly)
from Experiment import *
And yes, the strongly typed schema is now there for me to play with...
The experiment schema contains among other things an "Order" type, which holds a collection of "OrderLine" line's... so we can now do this:
order = Order()
line1 = OrderLine()
line1.UnitCost = 30
line1.NumberOfUnits = 2
order.OrderLines.Add(line1)
order.Save()
I think it makes quite a handy diagnostic tool, especially when you start considering that your dev, test and live environments may all have different schema versions... it could certainly save a lot of stuffing around - it would be fairly tedious to repeat this exercise in C# by comparison (especially once you've written a few useful helper functions in your own "base4" python module... I could shorten this entire post to 3 or 4 lines instead).
 Friday, November 03, 2006
IronPython on ASP.Net ?
Yes, that's right... dynamic language support in ASP.Net ... and some interesting things I didn't know existed in ASP.Net already, such as no-compile pages - well worth a skim through the whitepaper here (http://www.asp.net/ironpython/WhitePaper.aspx?tabid=62) - it's an interesting approach to bringing in dynamic language support to asp.net - and would certainly work for ruby on the CLR as well... probably better actually because ruby's statements are balanced and so you have less problem with whitespace.
Speaking of the deadly space that is white, It will be interesting to see if they've dealth with this horrible python integration issue at all...
I haven't seen any evidence of whitespace agnostic additions in the sample code that's been posted, so I'm guessing not... in which case there may be tears before bed time for some developers who want to do quick-and-dirty asp-like code (which I see is one of the advantages of using a dynamic language in this situation) ... As it all tends to blow up in your face when your tabs are slightly out of line - something which visual studio might just do for you when it feels like shuffling your html ;o)
I'm not sure how easy it would be to introduce a whitespace agnostic mode in IronPython for ASP.Net (Boo's whitespace agnostic mode, as used in Brail is quite elegant... the alternative is to do something like the spyce framework, using opening and closing braces... which just looks mucky to me because you end up with stuff like this:
[[ if display:{ ]] <strong>something here</strong> [[ }else:{ ]] <strong>nothing here</strong> [[ } ]]
Seems a bit too noisey... the "if display:" is enough to know you need to locate a matching closing block, so adding a construct like "end" should do the trick... which is how it's done in Brail...
<%if display:%>
<strong>something here</strong> <%else:%>
<strong>nothing here</strong> <%end%>
As clean as...
 Thursday, November 02, 2006
Castle goes RC2
Well it's an exciting week for Castle users, RC2 is out the door, and with it a new website look and feel with up-to-date content, and most interesting to me is the introduction of a new entity "CastleStronghold" a commercial venture, run by Hammet which offers professional support for developers and organisations implementing solutions in Castle, including guaranteed response times to inquiries and access to additional skilled development resources.
Personally Castle Stronghold is great news, as a developer for a company which has been using the Castle IoC for over a year now it adds a certain weight to our decision to run with this technology, and I think it offers a clear indication of the longevity this technology and product has... In time as our customer base grows it certainly looks appealing to have guaranteed support backing us up - and also helps customers to understand it's not some half backed open source project that's just going to fizzle out one day...
The RC2 release itself is exciting from a community point of view, it should be better then ever for people to pick up and play with this stuff - though we generally use interim snapshots of the trunk (ie. the last trunk release that didn't break our build...) so we've been exposed to most of the features for a while now, albeit without alot of the bug fixes ;o)
IronPython
I've been a bit quiet on the IronPython front... which is mostly because I haven't had the time to play around with it much lately - however I'll try to finish off my look into IronPython as a scripting engine, and in particular the good and bad aspects of getting it to play with your .Net code... In the mean time a collection of useful IronPython links is slowly growing here: http://ironpython-urls.blogspot.com/
Base4.Net
A week into using the Base4.Net's latest release, with compile-time query support, I'm loving it... it definitely gives a huge leap in productivity and expressability (if that's even a word ;o) - looking forward to seeing these features rounded out at some point (with support for scopes, projections and ordering) - Alex James is talking about migrations (my "most-wanted" feature) and it's looking encouraging, it's where I feel the most pain at the moment as base4 isn't particularly friendly when you try to approach the problem of building your schema in a YAGNI fashion - there is quite a bit of pain involved in adding and removing properties from types during development as requirements are refined.
The rub is that the current "on the table" solution will require restarting the base4 service to apply the migration... which at the moment means restarting the windows service with a different command line... or more likely, stopping the service, then starting the standalone server with the right command line arguments, waiting till it's done, stopping the standalone server and starting the service again... I was originally thinking of implementing these as a Nant or MSBuild task (much like RoR's migrations work with rake) but I think it might be a bit chunky... I need to think about it a bit more.
Splicer
I haven't forgot about my little side project (Splicer is a library I've written for "attempting" to eliminate the pain of using DirectShow.Net to encode audio and video) - and I do intend to keep updating and supporting it as-needed ... next release should see WinForm samples for encoding audio and video added, and updated code examples... after that I might review the implementation a bit, to see how effects and transitions can be made easier to use via relative times - I'm interested in DSL's at the moment, so maybe I could create a DSL for video editing ;o)... if nothing else it would be amusing... I've yet to establish if anyone actually uses the library yet (other than myself of course).
 Tuesday, October 31, 2006
Though I knew you could do it, I never have till today... and that's supplying a type for a generic parameter in another type, which is registered in a container... Of course I didn't have to do it that way, but it it kept the configuration a little thinner.
Basically I have some simple WCF services I wanted to host in a container.. here's the service's interface...
[ServiceContract(Namespace="http://localhost/schemas/testrunner/", SessionMode=SessionMode.Required)]
public interface ITestRunner
{
[OperationContract]
Guid StartTestRun(Guid testSuiteId);
[OperationContract]
TestRunStatus GetRunStatus(Guid testRunId);
}
To get this to work for my implementation I had to do one thing, which was set the InstanceContextMode to "single" for the service implementations behaviour, otherwise the service host would die when I tried to pass in an instance (it expects a type for any other mode)... I haven't dug very deep into WCF, but it would be nice if they supported a mechanism for supplying a component activator instead...
[ ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class TestRunner : ITestRunner
{
Now, I build a component for hosting my service... it implements IStartable...
public class HostingWrapper<T> : IStartable
where T: class
{
private ServiceHost _host;
private T _service;
private ILogger _log;
public HostingWrapper(ILogger log, T service)
{
if (log == null) throw new ArgumentNullException("log");
if (service == null) throw new ArgumentNullException("service");
_log = log;
_service = service;
}
public void Start()
{
_host = new ServiceHost(_service);
if (_log.IsDebugEnabled) _log.Debug("Opening ServiceHost for service: {0}", _service.GetType());
_host.Open();
if (_log.IsInfoEnabled) _log.Info("Opened ServiceHost for service: {0}", _service.GetType());
}
public void Stop()
{
if (_log.IsDebugEnabled) _log.Debug("Closing ServiceHost for service: {0}", _service.GetType());
_host.Close();
((IDisposable)_host).Dispose();
if (_log.IsInfoEnabled) _log.Info("Closed ServiceHost for service: {0}", _service.GetType());
_host = null;
}
}
And then you just need to regsiter it in the container's configuration:
<components>
<component id="testRunnerService.default"
service="BoatsForGoats.Services.Testing.ITestRunner, BoatsForGoats.Services"
type="BoatsForGoats.Services.Testing.TestRunner, BoatsForGoats.Services" />
<component id="testRunnerHost.default"
type="BoatsForGoats.Services.HostingWrapper`1[[BoatsForGoats.Services.Testing.ITestRunner, BoatsForGoats.Services]], BoatsForGoats.Services" />
About the only tricky thing is that I guessed (incorrectly) that I would only need a single set of square brackets around the generic parameter.
 Thursday, October 26, 2006
Well lots to blog about, but no time to do it... at least not
today - at any rate I just thought I would say if you haven't
considered using Base4 up until now, why not give it a go with the latest drop
:) I'm loving these new changes with the support for Compile-time query
handling... I think at this point you can start prototyping stuff with
base4 very quickly, between the UI for designing or discovering an
existing schema, and now the ability to avoid learning the ObjectPath
query syntax it's pretty compelling...
At any rate, as mentioned in the various posts from Alex James, you can now write these kinds of queries:
IItemList<FileBase> matchingFiles = StorageContext.Find<FileBase>(FileBase.Fields.FileSize > 1024000 && FileBase.Fields.MimeType == "audio/wav");
Faboo, and of course you can drill through the relationships:
Track track = StorageContext.FindOne<Track>(Track.Fields.Name == reference.TrackName
&& Track.Fields.Release.Name == reference.ReleaseName
&& Track.Fields.Release.Artist.Name == reference.ArtistName);
This is for a simple hierarchy, where we have Artists-> Releases
-> Tracks (sadly organising Music in reality isn't quite this
easy...)
But as you can see these queries are getting quite verbose, personally
this is where the elegance of this approach comes in... reuse is
possible, for example - we can build a static class to hold common
queries:
public static class FileBaseQueries
{
public static ExpressionField LargerThenOneMegabyte
{
get
{
return FileBase.Fields.FileSize > 1024000;
}
}
public static ExpressionField MimeTypeIsAudioWav
{
get
{
return FileBase.Fields.MimeType == "audio/wav";
}
}
}
And now the first query could be rewritten:
StorageContext.Find<FileBase>(FileBaseQueries.LargerThenOneMegabyte && FileBaseQueries.MimeTypeIsAudioWav);
The main thing I like about this approach is your queries start looking
like sentences... "Larger Then One Megabyte and Mime Type Is Audio
Wav"...
Another idea might be to use a method on the static class instead...
public static ExpressionField MimeTypeIs(string type, string subType)
{
return FileBase.Fields.MimeType == string.Format("{0}/{1}", type, subType);
}
And then writing something like:
StorageContext.Find<FileBase>(FileBaseQueries.LargerThenOneMegabyte && FileBaseQueries.MimeTypeIs("audio","wav"));
At this point it still reads quite nicely, but it's a little more flexible...
Edit: I just noticed this entry wasn't actually marked as syndicated... fixed it now.
 Thursday, October 19, 2006
I think there's 3 levels of skill involved with the
Castle IoC implementation... first off you get a handle of the XML
configuration, registering components, using existing facilities...
pretty much getting away largely with cut 'n paste coding.
Then you get to the intermediate level.. writing basic facilities,
tweaks to the component model, writing your own sub dependency
resolvers or component activator, having a go with binsor configuration.
I think the third level is reserved for the Castle team alone... ;o)
This post is going to be straddling the beginner to intermediate kinda
level... which is generally all I ever reach with Castle's IoC... it's
not often you have to dig deeper day-to-day... though it's always good
to know there is a lot of untapped potential there.
So.. for today, say you have a component, like the Base4Host, which has some explicit constructors:
public Base4Host(string appName, int port)
{
if (string.IsNullOrEmpty(appName)) throw new ArgumentNullException("appName");
if (port <= 1024) throw new ArgumentOutOfRangeException("port", "port should be greater then 1024");
_appName = appName;
_port = port;
}
public Base4Host(string appName, int port, string root)
: this(appName, port)
{
if (string.IsNullOrEmpty(root)) throw new ArgumentNullException("root");
_root = root;
}
You can register it the container easy enough, and provide values for
them in XML configuration, but what if you want to do the same programatically... generally
your first stop would be to examine the IWindsorContainer for a
suitable overload... alas it doesn't get us far, so we dig in to the
underlying IKernel itself... the kernel exposes some possible candidates:
void AddComponentWithExtendedProperties(String key, Type classType, IDictionary extendedProperties);
void AddComponentWithExtendedProperties(String key, Type serviceType, Type classType, IDictionary extendedProperties);
So you experiment with them, but supplying the dictionary of extended
properties does nothing... hmm... time to file a bug report? well no...
extended properties having nothing to do with satisfying parameter or
property dependencies on your component - not directly at least.
So why don't we just create the component ourselves.. and then add it to the container?
Well you can, via the Kernel.AddComponentInstance method but
you're going to miss out on some things... for instance the startable
facility won't be "concerned" with your component, and as such if it
implements IStartable it won't get started and stopped... Though I haven't confirmed this, I dont think the container will bother to dispose of any IDisposable
components registered in this fashion either... the container doesn't
consider itself the owner of the component (and generally this is what
we want).
So we're going to have to get a little more intimate with the container
implementation ... so every time a component is registered in the
container a corresponding ComponentModel is generated for the component, this basically keeps track of the:
- Components dependencies
- Constructor candidates
- Parameters (sounds like us...)
- Name, implementation type and service type.
- Lifecycle, Lifestyle...
- And some other stuff you can discover for yourself.
Now we could get heavy handed and jump into contributing to the
construction of the component model itself... but it's pretty
uncessary, we just want to tweak the end result... so we can use an
event handler on the Kernel - ComponentModelCreated.
So here we have an implementation that solves our problems... This is
being implemented inside a facility, but you could do this anywhere...
wire it up in your custom container that's derived from WindsorContainer maybe, obviously you want to remove the if statement for checking the Implemenation type is Base4Host though. :)
private const string AdditionalParametersKey = "AdditionalParameters";
private void Kernel_ComponentModelCreated(Castle.Core.ComponentModel model)
{
if (model.Implementation == typeof(Base4Host))
{
if ((model.Configuration == null)
&& model.ExtendedProperties.Contains(AdditionalParametersKey))
{
Dictionary<string, object> additionalParameters = (Dictionary<string, object>)model.ExtendedProperties[AdditionalParametersKey];
foreach (string parameterName in additionalParameters.Keys)
{
model.Parameters.Add(parameterName, Convert.ToString(additionalParameters[parameterName]));
}
}
}
}
protected override void Init()
{
Kernel.ComponentModelCreated += new ComponentModelDelegate(Kernel_ComponentModelCreated);
}
Now I can register my component by doing something like this:
Dictionary<string, object> additionalParameters = new Dictionary<string, object>();
additionalParameters.Add("appName", _applicationName);
additionalParameters.Add("port", _port);
additionalParameters.Add("root", _baseDirectory);
Hashtable properties = new Hashtable();
properties.Add(AdditionalParametersKey, additionalParameters);
Kernel.AddComponentWithProperties("base4.defaultHost", typeof(Base4Host), properties);
Here we're passing all our additional parameters as a Dictionary<string, object> inside
our IDictionary of additional properties.... this isn't the most
elegant implementation, but this is all code internal to a single
facility so it's not really important to me... and it gets the job done just fine.
 Tuesday, October 17, 2006
Abstractions... mmmm... so sweet...a post from Ayende on abstractions, and specifically a mention of the logging "abstraction" in Castle... it's an interesting thing, for the Seismic product I worked logging (via the same abstraction) into a product a year or more ago... in the end we needed the ability to log contextual information (basically exposing features already existing in log4net at the time, but not available via the Castle ILogger interface) and so I ended up creating a new interface that was a superset of the existing abstraction, IExtendedLogger... here's the devil... looks simple...
public interface IExtendedLogger : ILogger
{
void AddProperty(string key, object value);
void RemoveProperty(string key);
}
However... because we're being a good little abstraction "whore" we end up with a few more classes to support this new interface, and make the user experience more pleasurable:

Though I was reasonably pleased with the end result a year ago, that was probably a couple of hours work + some more time tweaking (once you include the time to code up that test fixtures) that would've been better spent building additional functionality into the product.
I have to admit the lure of a needless abstraction is ever present to me... I enjoy halving a class into an abstract and concrete implementation, and then extracting an interface is like the candy coating... prefixing the concrete implementation with "Default" makes it even seem like you've all but got people lining up to create their own versions! Wow, isn't it powerful, flexible.. and all sorts of other words ending in "ul" or "ile".
....But in the end, needless is needless - and I haven't needed the flexibility gained from this abstraction so far... after a year... a whole year, that's pretty much like never... sure I had grand plans, but they never did come to fruition... and grand plans don't keep me fed - YAGNI strikes again.
About the only thing I find the needless abstractions do is in clarifying my thinking on what I do and don't need, or more importantly what I do and don't want people to do with my code.... it let's me define just what I want my "pit of success" behavior to be, albeit not the implementation... Perhaps some of this stuff is better reserved for throw away prototypes then production code.
I think the best book I've found for discouraging this "80's guitar solo" of abstraction..um...ism is the Framework Design Guidelines... Though these abstractions do make it easy for me to maintain and grow my code (and the orthogonality of the design is generally good) it comes at the price of other people having difficulty learning my API through experimentation, and I fail to create a progressive framework... which after reading the aforementioned book, is something we all wan't to do.
I guess the final question is, do you reverse an abstraction that isn't required after such a long time...? Or do you just avoid making the same mistake twice and live with the abstraction, assuming it's not hurting too many people - Is it worth lumping it with the rest of the "broken windows" in a project, or is that a little too brash?
Startable facility and hosting base4Ivan's pretty keen :) last week he demonstrated hosting the base4 service in ASP.Net ... cool stuff. Now here he has placed the implementation in the HttpApplication class, and as a quick observation this would be a good candidate for moving into it's own component... and as luck would have it, Castle has just the thing, via the Startable facility.
Startable... (and the implied, stoppable ;o)Now the startable facility is a very simple beast, basically... you create a class, that implements this interface:
/// <summary>
/// Interface for components that wish to be started by the container
/// </summary>
public interface IStartable
{
void Start();
void Stop();
} Which lives in the Castle.Core assembly... though the facility itself lives in the Castle.MicroKernel assembly... you should already have references to both, otherwise I doubt your container is working at all :P And you then register the startable facility in the container:
<facility id="startable.facility"
type="Castle.Facilities.Startable.StartableFacility, Castle.MicroKernel" /> And thats it... now whenever you register a component in the container, the startable facility will check it, and if it's found to implement IStartable it will add it to a list of components "awaiting startup"... once any of these awaiting components has had all it's dependencies satisfied it will be started (so it may be started as soon as the component is registered, if it doesn't have any dependencies - this will be the case for our component)... Disposing of the container will cause the components to be stopped in turn... perfect for hosting our base4 server...
Reworking the hosting code to be a startable component......so taking what Ivan's done, we could rework it a little... and be able to host base4 in web apps, as well as say your business logic's test harness... here's my quick 'n dirty reworked implementation as a component that I did this afternoon... my final version probably won't have any dependencies on the HttpContext as I'll just rely on explicit declaration of all the settings as parameters in the container configuration... I tend to like keeping all the config in the container, one place to look 'n all that.
public class Base4Host : IStartable
{
private const string _machineName = "localhost";
private const string _provider = "SQL2005";
private string _appName;
private int _port;
private string _root;
private ServerConfiguration _configuration;
private IServerProxy _proxy;
public ServerConfiguration Configuration
{
get { return _configuration; }
}
public IServerProxy ServerProxy
{
get { return _proxy; }
}
public Base4Host(string appName, int port)
{
if (string.IsNullOrEmpty(appName)) throw new ArgumentNullException("appName");
if (port <= 1024) throw new ArgumentOutOfRangeException("port", "port should be greater then 1024");
_appName = appName;
_port = port;
}
public Base4Host(string appName, int port, string root)
: this(appName, port)
{
if (string.IsNullOrEmpty(root)) throw new ArgumentNullException("root");
_root = root;
}
#region IStartable Members
public void Start()
{
_configuration = CreateConfiguration();
_proxy = ServerFactory.StartServer(_configuration, false);
string base4Context = string.Format("tcp://Server:@localhost:{0}/{1}", _port, _appName);
StorageContext.SetDefault(base4Context);
}
public void Stop()
{
_proxy.Stop();
_proxy = null;
_configuration = null;
}
#endregion
#region Support methods
private ServerConfiguration CreateConfiguration()
{
ServerConfiguration configuration = new ServerConfiguration();
DiscoverApplicationName();
InsertApplicationRoot(configuration);
InsertConnectionStrings(configuration);
InsertConnectivityInformation(configuration);
if (!Directory.Exists(configuration.Store.Root))
{
Directory.CreateDirectory(configuration.Store.Root);
}
return configuration;
}
private void InsertConnectivityInformation(ServerConfiguration configuration)
{
configuration.Store.Name = _appName;
configuration.Store.Provider = _provider;
configuration.Store.Port = _port;
configuration.Store.MachineName = _machineName;
}
private void DiscoverApplicationName()
{
if (string.IsNullOrEmpty(_appName))
{
if (HttpContext.Current.Application["AppName"] == null)
{
Assembly assembly = Assembly.GetCallingAssembly();
HttpContext.Current.Application["AppName"] = (AssemblyTitleAttribute.GetCustomAttribute(assembly, typeof(AssemblyTitleAttribute)) as AssemblyTitleAttribute).Title;
}
_appName = HttpContext.Current.Application["AppName"].ToString();
}
}
private void InsertApplicationRoot(ServerConfiguration configuration)
{
string root = string.IsNullOrEmpty(_root) ? HttpContext.Current.Server.MapPath("~/") : _root;
configuration.Store.Root = root.EndsWith("\\") ? root + "App_Data\\Base4" : root + "\\App_Data\\Base4";
}
private void InsertConnectionStrings(ServerConfiguration configuration)
{
string connectionStringName = ConfigurationManager.AppSettings["DefaultConnection"];
if (string.IsNullOrEmpty(connectionStringName) && ConfigurationManager.ConnectionStrings != null
&& ConfigurationManager.ConnectionStrings.Count > 0)
{
connectionStringName = ConfigurationManager.ConnectionStrings[0].Name;
}
configuration.Store.ConnectionString = string.IsNullOrEmpty(connectionStringName) ? ConfigurationManager.AppSettings["Store.ConnectionString"] :
ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
SqlConnectionStringBuilder connStrBuilder = new SqlConnectionStringBuilder(configuration.Store.ConnectionString);
connStrBuilder.InitialCatalog = "master";
configuration.MasterConnectionString = connStrBuilder.ToString();
}
#endregion
} Notice we don't expose a default constructor... how can the container create it? Well, it can't unless we supply the parameters it requires... which is just what we'll do:
<component
id="base4host.default"
type="MyProject.Base4Host, MyProject">
<parameters>
<appName>GoatsAndBoats</appName>
<port>11888</port>
</parameters>
</component> Simple... a couple of useful extensions to our existing base4 facility may well be to:
- Ensure the startable facility is installed... so we can fail-early and with a meaningful error during application startup.
- Add some additional "optional" parameters for configuring the facility, so that it can take care of registering the Base4Host for us.
For the optional parameters, I'm thinking of doing something like this:
<facility id="base4.storageFacility"
type="SomeProject.Core.Base4StorageFacility, SomeProject.Core"
host="true"
appName="GoatsAndBoats"
port="11888"
connectionString="local"
/> At which point it's trivial to shift between accessing base4.net as a remote service vs. hosting it in your own app... unlike the remote setup you can skip providing the base4 url (context string) as it'll be implied from the app name and port.
 Monday, October 16, 2006
Trac
I know it's not .Net, but that's not always a bad thing...
Well I tend to keep my eye out for things which take my fancy, or more importantly, free things that take my fancy...
Trac
is one of those things, a project management and bug database web app
written in Python, written by edgewall software... it's actually pretty cool... for RoR enthusiasts
they're probably aware of it's existence already (considering RoR use this for manging their bugs and patches)
First off, you can run it on windows... though a *nix is generally better, and it's not too hard to
get going - took me about half an hour... second thing, it's a lot
better once you install a few hacks especially:
Now, at this point what makes it good?
- SVN Integration
- Wiki Integration
- Extensibility and community support
Basically I can check in code with comments containing wiki markup
and
references to existing "tickets" logged in the system... The wiki
integration incidentally is my primary motivation for looking so
closely at using this for some of the projects I've been working on...
I'm a liability to Seismic Technologies... documenting build processes
etc. in a wiki are one way we
can minimize that... We already have a customer-focused wiki, but it
doesn't encourage maintenance on a day-to-day basis like this product
does.
secondary to that is the very good subversion integration, a must
considering that's the only source control system I use.
Creating tickets via XML-RPC in C#
Now the last hack I suggested exposes plenty of functionality in the
system via XML RPC... at which point we can start logging bugs
remotely, from C#... to do this we'll need a copy of the xmlrpc.net library
I'm not conducting a tutorial here ;o) but if Trac takes your fancy you
might find this code handy... first off this is our interface for logging
tickets in Trac - incidentally this is only a small subset of the funcionality exposed.
[XmlRpcUrl("http://localhost/trac/login/xmlrpc")]
public interface ITicket : IXmlRpcProxy
{
[XmlRpcMethod("ticket.query")]
int[] Query(string qstr);
[XmlRpcMethod("ticket.getRecentChanges")]
int[] GetRecentChanges(DateTime since);
[XmlRpcMethod("ticket.getAvailableActions")]
string[] GetAvailableActions(int id);
[XmlRpcMethod("ticket.getTicketFields")]
TicketField[] GetTicketFields();
[XmlRpcMethod("ticket.create")]
int Create(string summary, string description, XmlRpcStruct attributes);
[XmlRpcMethod("ticket.get")]
object[] GetTicket(int id);
[XmlRpcMethod("ticket.delete")]
void Delete(int id);
[XmlRpcMethod("ticket.update")]
object[] Update(int id, string comment, XmlRpcStruct attributes);
[XmlRpcMethod("ticket.type.getAll")]
string[] GetAllTypes();
[XmlRpcMethod("ticket.resolution.getAll")]
string[] GetAllResolutions();
[XmlRpcMethod("ticket.priority.getAll")]
string[] GetAllPriorities();
[XmlRpcMethod("ticket.component.getAll")]
string[] GetAllComponents();
[XmlRpcMethod("ticket.version.getAll")]
string[] GetAllVersions();
[XmlRpcMethod("ticket.severity.getAll")]
string[] GetAllSeverities();
[XmlRpcMethod("ticket.milestone.getAll")]
string[] GetAllMilestones();
}
Now, tickets have a bunch of attributes associated with them...
public static class TicketAttributes
{
public const string Cc = "cc";
public const string Keywords = "keywords";
public const string Status = "status";
public const string Type = "type";
public const string Owner = "owner";
public const string Version = "version";
public const string Resolution = "resolution";
public const string Reporter = "reporter";
public const string Milestone = "milestone";
public const string Component = "component";
public const string Summary = "summary";
public const string Description = "description";
public const string Priority = "priority";
}
And we can make ticket information easier to get a hold of with a simple class:
/// <summary>
/// represents the information for a ticket
/// </summary>
public class TicketInfo
{
private int _ticketId;
private DateTime _created;
private DateTime _lastModified;
private XmlRpcStruct _attributes;
public TicketInfo()
{
}
public TicketInfo(object[] values)
{
Update(values);
}
internal void Update(object[] values)
{
if (values == null) throw new ArgumentNullException("values");
if (values.Length != 4) throw new ArgumentException("values should have 4 elements");
_ticketId = (int)values[0];
_created = DateHelper.ParseUnixTimestamp((int)values[1]);
_lastModified = DateHelper.ParseUnixTimestamp((int)values[2]);
_attributes = (XmlRpcStruct)values[3];
}
/// <summary>
/// The identifier for this ticket
/// </summary>
public int TicketId
{
get { return _ticketId; }
set { _ticketId = value; }
}
/// <summary>
/// date and time the ticket was created
/// </summary>
public DateTime Created
{
get { return _created; }
set { _created = value; }
}
/// <summary>
/// date and time the ticket was last modified
/// </summary>
public DateTime LastModified
{
get { return _lastModified; }
set { _lastModified = value; }
}
/// <summary>
/// The attributes for this ticket, this will include any additional fields
/// that aren't defined explicitly as members of this class.
/// </summary>
public XmlRpcStruct Attributes
{
get
{
if (_attributes == null) _attributes = new XmlRpcStruct();
return _attributes;
}
set { _attributes = value; }
}
public string Cc
{
get { return GetAttribute(TicketAttributes.Cc); }
set { SetAttribute(TicketAttributes.Cc, value); }
}
public string Keywords
{
get { return GetAttribute(TicketAttributes.Keywords); }
set { SetAttribute(TicketAttributes.Keywords, value); }
}
public string Status
{
get { return GetAttribute(TicketAttributes.Status); }
set { SetAttribute(TicketAttributes.Status, value); }
}
public string Type
{
get { return GetAttribute(TicketAttributes.Type); }
set { SetAttribute(TicketAttributes.Type, value); }
}
public string Owner
{
get { return GetAttribute(TicketAttributes.Owner); }
set { SetAttribute(TicketAttributes.Owner, value); }
}
public string Version
{
get { return GetAttribute(TicketAttributes.Version); }
set { SetAttribute(TicketAttributes.Version, value); }
}
public string Resolution
{
get { return GetAttribute(TicketAttributes.Resolution); }
set { SetAttribute(TicketAttributes.Resolution, value); }
}
public string Reporter
{
get { return GetAttribute(TicketAttributes.Reporter); }
set { SetAttribute(TicketAttributes.Reporter, value); }
}
public string Milestone
{
get { return GetAttribute(TicketAttributes.Milestone); }
set { SetAttribute(TicketAttributes.Milestone, value); }
}
public string Component
{
get { return GetAttribute(TicketAttributes.Component); }
set { SetAttribute(TicketAttributes.Component, value); }
}
public string Summary
{
get { return GetAttribute(TicketAttributes.Summary); }
set { SetAttribute(TicketAttributes.Summary, value); }
}
public string Description
{
get { return GetAttribute(TicketAttributes.Description); }
set { SetAttribute(TicketAttributes.Description, value); }
}
public string Priority
{
get { return GetAttribute(TicketAttributes.Priority); }
set { SetAttribute(TicketAttributes.Priority, value); }
}
#region Support methods
private string GetAttribute(string name)
{
if (Attributes.Contains(name))
{
return Convert.ToString(Attributes[name]);
}
return null;
}
private void SetAttribute(string name, string value)
{
if (Attributes.Contains(name))
{
Attributes[name] = value;
}
else
{
Attributes.Add(name, value);
}
}
#endregion
}
And last of all we have a class for managing tickets.. by the way
this isn't complete, I haven't finished writing it because this is just
one of my back burner projects...
public class TicketManager
{
private ITicket _ticket;
public void Connect(string url, string userName, string password)
{
_ticket = XmlRpcProxyGen.Create<ITicket>();
_ticket.Url = url;
_ticket.PreAuthenticate = true;
_ticket.Credentials = new NetworkCredential(userName, password);
}
public string[] GetAvailableActions(int id)
{
return _ticket.GetAvailableActions(id);
}
public string[] GetAvailableActions(TicketInfo ticket)
{
ValidateTicket(ticket);
return _ticket.GetAvailableActions(ticket.TicketId);
}
public int[] GetRecentChanges(DateTime since)
{
return _ticket.GetRecentChanges(since);
}
public void DeleteTicket(int ticketId)
{
_ticket.Delete(ticketId);
}
public void DeleteTicket(TicketInfo ticket)
{
ValidateTicket(ticket);
DeleteTicket(ticket.TicketId);
}
public void UpdateTicket(TicketInfo ticket, string comment)
{
ValidateTicket(ticket);
object[] values = _ticket.Update(ticket.TicketId, comment, ticket.Attributes);
ticket.Update(values);
}
public void CreateTicket(TicketInfo ticket)
{
if (string.IsNullOrEmpty(ticket.Summary)) throw new ArgumentNullException("ticket.Summary");
if (string.IsNullOrEmpty(ticket.Description)) throw new ArgumentNullException("ticket.Description");
if (string.IsNullOrEmpty(ticket.Type)) throw new ArgumentNullException("ticket.Type");
if (string.IsNullOrEmpty(ticket.Priority)) throw new ArgumentNullException("ticket.Priority");
if (string.IsNullOrEmpty(ticket.Component)) throw new ArgumentNullException("ticket.Component");
XmlRpcStruct tempAttributes = new XmlRpcStruct();
foreach (object key in ticket.Attributes.Keys)
{
if ((((string)key) != TicketAttributes.Description) && (((string)key) != TicketAttributes.Summary))
{
tempAttributes.Add(key, ticket.Attributes[key]);
}
}
int id = _ticket.Create(ticket.Summary, ticket.Description, ticket.Attributes);
ticket.TicketId = id;
}
private void ValidateTicket(TicketInfo ticket)
{
if (ticket == null) throw new ArgumentNullException("ticket");
if (ticket.TicketId <= 0) throw new ArgumentException("ticketId must be greater then 0");
}
}
About the only trick here is that some of the date values get returned as unix time stamps so you need to convert them...
public static DateTime ParseUnixTimestamp(double timestamp)
{
return new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(timestamp);
}
Because the Syzmk Rich Media Processor product I work on is a clearing
house for simple messages among other things... It becomes a small jump from
here (about 30 lines of C# code, 5 for a quick and dirty "IronPython" script) to start submitting tasks and bugs via
email or mobile... who knows, it could be handy if you get a call
while your out of the office and need to log a bug or task.
Monorail Pagination with Base4.Net
So, part of today was spent building "digg" style pagination for
data I'm pulling out of base4... if you don't use digg, then what I
mean is stuff like this:
Flickr and plenty of other sites use the same layout... and it does
seem quite a convenient way to work your way through large result
sets...
Fairly standard stuff, because I'm using monorail my first pit stop was the pagination helper
- however there's a bit of an impedance mismatch here, as the
pagination helper is geared towards paging through an IList containing
all the records, where as generally speaking you're working with
IItemList<T> and wanting to make use of the inherent
paging support in base4.net... hmmm... at any rate, this isn't exactly
"brilliant" code - but it might prove useful if you messing around with
Monorail at home - something I think you should do.
Paging and base4.net
So, first off, I built a small class to represent a "page" from a larger
set of query results in my application... it looks like this...
/// <summary>
/// Represents a page from a query
/// </summary>
/// <typeparam name="T"></typeparam>
public class PagedItemList<T> : IEnumerable<T>
where T: class, IItem
{
private IItemList<T> _items;
private int _pageNumber;
private int _pageSize;
private int _totalCount;
public PagedItemList(IItemList<T> items, int pageSize, int pageNumber, int totalCount)
{
if (items == null) throw new ArgumentNullException("items");
if (pageNumber <= 0) throw new ArgumentOutOfRangeException("pageNumber", "pageNumber must be greater then 0");
if (pageSize <= 0) throw new ArgumentOutOfRangeException("pageSize", "pageSize must be greater then 0");
if (totalCount < 0) throw new ArgumentOutOfRangeException("totalCount", "totalCount must be greater then or equal to 0");
_items = items;
_pageNumber = pageNumber;
_pageSize = pageSize;
_totalCount = totalCount;
}
/// <summary>
/// The count of items on this page
/// </summary>
public int PageCount
{
get { return (int)Math.Ceiling(((double)TotalCount) / ((double)PageSize)); }
}
/// <summary>
/// Index of the first item on this page
/// </summary>
public int FirstItemIndex
{
get
{
return PageSize * (PageNumber-1);
}
}
/// <summary>
/// Index of the last item on this page
/// </summary>
public int LastItemIndex
{
get
{
return Math.Min(FirstItemIndex + (PageSize - 1), TotalCount - 1);
}
}
/// <summary>
/// 1-relative page number index
/// </summary>
public int PageNumber
{
get
{
return _pageNumber;
}
}
/// <summary>
/// The size of each page
/// </summary>
public int PageSize
{
get { return _pageSize; }
}
/// <summary>
/// Total number of results returned from the query
/// </summary>
public int TotalCount
{
get { return _totalCount; }
}
/// <summary>
/// Number of items on this page
/// </summary>
public int Count
{
get { return _items.Count; }
}
/// <summary>
/// the underlying list of items
/// </summary>
public IItemList<T> Items
{
get { return _items; }
}
public IEnumerator<T> GetEnumerator()
{
return _items.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((IEnumerable)_items).GetEnumerator();
}
}
Pretty mundane, next we just extend my existing repository with a new method for returning a PagedItemList<T>... here's how it looks:
public virtual PagedItemList<T> Find(ObjectQuery query, int pageSize, int pageNumber)
{
if (query == null) throw new ArgumentNullException("query");
if (pageSize <= 0) throw new ArgumentException("pageSize must be greater then 0");
if (pageNumber <= 0) throw new ArgumentException("pageNumber must be greater then 0");
int count = Convert.ToInt32(_context.ExecuteScalar(query.Compile().SELECT_COUNT()));
query.Path.PageSize = pageSize;
query.Path.PageNumber = pageNumber;
return new PagedItemList<T>(Find(query), pageSize, pageNumber, count);
}
For our query we first estabilsh the total count of results, then we
just run the query again and return the results for the selected page.
From Base4.Net to Monorail
Now, our PagedItemList<T> is useful by itself, but there's
a more feature-complete interface in monorail for representing a "page"
of informaton for display logic, used by the pagination helper, it's
called IPaginatedPage.
public interface IPaginatedPage : IEnumerable
{
int CurrentIndex { get; }
int LastIndex { get; }
int NextIndex { get; }
int PreviousIndex { get; }
int FirstIndex { get; }
int FirstItem { get; }
int LastItem { get; }
int TotalItems { get; }
bool HasPrevious { get; }
bool HasNext { get; }
bool HasFirst { get; }
bool HasLast { get; }
}
...so, we just build a little adaptor object, using the abstract base page
that implementes IPaginatedPage, called " AbstractPage" funnily enough - here I've
called my adaptor Base4Page.
public class Base4Page<T> : AbstractPage
where T: class, IItem
{
private PagedItemList<T> _items;
public Base4Page(PagedItemList<T> items)
{
if (items == null) throw new ArgumentNullException("items");
_items = items;
CalculatePaginationInfo(items.FirstItemIndex, items.LastItemIndex,
items.TotalCount, items.PageSize, items.PageNumber);
}
public override System.Collections.IEnumerator GetEnumerator()
{
return _items.GetEnumerator();
}
}
Soo... last of all, where's the pay off?
Well, first thing's first, now you can do this in your controller:
public void Users(int pageSize, int page)
{
ObjectQuery query = new ObjectQuery(typeof(Car));
// not enough set some further critiera...
PropertyBag.Add("Cars", new Base4Page<Car>(_carRepository.Find(query, pageSize, page)));
}
At which point, you could do some simple pagination in your views (and pagination
examples for existing Monorail websites can be cut 'n' pasted in to give you a head start)...
<table cellpadding="4"> <tr> <th>Make</th> <th>Model</th> <th>Year</th> </tr> #foreach($Car in $Cars) <tr> <td>$!Car.Make</td> <td>$!Car.Model</td> <td>$!Car.Year</td> </tr> #end </table> <div class="pagination" id="pagination"> <table width="90%" border="0"> <tr> <td>Showing $Cars.FirstItem - $Cars.LastItem of $Cars.TotalItems</td> <td align="right"> #if($Cars.HasFirst) $PaginationHelper.CreatePageLink( 1, "first", null, null) ) #end #if(!$Cars.HasFirst) first #end #if($Cars.HasPrevious) | $PaginationHelper.CreatePageLink( $Cars.PreviousIndex, "prev", null, null) ) #end #if(!$Cars.HasPrevious) | prev #end #if($Cars.HasNext) | $PaginationHelper.CreatePageLink( $Cars.NextIndex, "next",null, null) ) #end #if(!$Cars.HasNext) | next #end #if($Cars.HasLast) | $PaginationHelper.CreatePageLink( $Cars.LastIndex, "last",null, null) ) #end #if(!$Cars.HasLast) | last #end </td> </tr> </table> </div>
And of course it's not much harder to write the logic for displaying
"digg" style pagination.... I decided to write it as a helper in C#,
because after messing with it for 15 minutes in brail it pissed me off
too much (some things in brail are quite annoying compared to normal
boo, for instance I couldn't seem to use the "range(...)" builtin, and
if your view doesn't have any content after the last <% ... %>
block it throws up a compile time exception... Admittedly I haven't
done a get latest from the Castle site in a couple of weeks... so this
might not actually be a problem any more, or maybe I just don't have the brail engine configure "just right".
public abstract class AbstractDiggPaginationHelper : AbstractHelper
{
public string CreateDiggPagination(IPaginatedPage page, int adjacents)
{
return CreateDiggPagination(page, adjacents, null);
}
public string CreateDiggPagination(IPaginatedPage page, int adjacents, IDictionary queryStringParams)
{
StringBuilder output = new StringBuilder();
WriteLink(output, page.PreviousIndex, "« prev", !page.HasPrevious, queryStringParams);
if (page.LastIndex < (4 + (adjacents * 2))) // not enough links to make it worth breaking up
{
WriteNumberedLinks(output, page, 1, page.LastIndex, queryStringParams);
}
else
{
if ((page.LastIndex - (adjacents * 2) > page.CurrentIndex) && // in the middle
(page.CurrentIndex > (adjacents * 2)))
{
WriteNumberedLinks(output, page,
1, 2, queryStringParams);
WriteElipsis(output);
WriteNumberedLinks(output, page,
page.CurrentIndex - adjacents, page.CurrentIndex + adjacents,
queryStringParams);
WriteElipsis(output);
WriteNumberedLinks(output, page,
page.LastIndex - 1, page.LastIndex, queryStringParams);
}
else if (page.CurrentIndex < (page.LastIndex /2))
{
WriteNumberedLinks(output, page,
1, 2 + (adjacents * 2), queryStringParams);
WriteElipsis(output);
WriteNumberedLinks(output, page,
page.LastIndex - 1, page.LastIndex, queryStringParams);
}
else // at the end
{
WriteNumberedLinks(output, page,
1, 2, queryStringParams);
WriteElipsis(output);
WriteNumberedLinks(output, page,
page.LastIndex - (2 + (adjacents * 2)), page.LastIndex,
queryStringParams);
}
}
WriteLink(output, page.NextIndex, "next »", !page.HasNext, queryStringParams);
return output.ToString();
}
private void WriteElipsis(StringBuilder builder)
{
builder.Append("...");
}
private void WriteNumberedLinks(StringBuilder builder, IPaginatedPage page, int startIndex, int endIndex, IDictionary queryStringParams)
{
for (int i=startIndex; i<= endIndex; i++)
{
WriteNumberedLink(builder, page, i, queryStringParams);
}
}
private void WriteLink(StringBuilder builder, int index, string text, bool disabled, IDictionary queryStringParams)
{
if (disabled)
{
builder.AppendFormat("<span class=\"disabled\">{0}</span>", text);
}
else
{
WritePageLink(builder, index, text, null, queryStringParams);
}
}
private void WriteNumberedLink(StringBuilder builder, IPaginatedPage page, int index, IDictionary queryStringParams)
{
if (index == page.CurrentIndex)
{
builder.AppendFormat("<span class=\"current\">{0}</span>", index);
}
else
{
WritePageLink(builder, index, index.ToString(), null, queryStringParams);
}
}
protected abstract void WritePageLink(StringBuilder builder, int page, String text, IDictionary htmlAttributes, IDictionary queryStringParams);
}
The guts of the helper is in an abstract class, simply so I could test
the numbering logic without having to worry about creating a controller
& http context (just implement the WritePageLink method with some simple text output ... the implementation is here:
public class DiggPaginationHelper : AbstractDiggPaginationHelper
{
protected override void WritePageLink(StringBuilder builder, int page, String text, IDictionary htmlAttributes, IDictionary queryStringParams)
{
string filePath = "";
if (CurrentContext != null)
{
filePath = CurrentContext.Request.FilePath;
}
if (queryStringParams == null)
{
queryStringParams = new Hashtable();
}
queryStringParams["page"] = page.ToString();
builder.AppendFormat("<a href=\"{0}?{1}\" {2}>{3}</a>", filePath, BuildQueryString(queryStringParams), GetAttributes(htmlAttributes), text);
}
}
At which point you can just register it on the controller, and call it
with something like ${DiggPaginationHelper.CreateDiggPagination(tracks,
3)} and
get yourself a nice little paging display. The second parameter
is the "adjacent" - which can be used to control how many pages are
displayed either side of the selected page when dealing with lots of
results.
Oh, and of course you might want some CSS to go with it...
/* pagination */
div.pagination {
padding: 3px;
margin: 3px;
}
div.pagination a {
color: #000099;
text-decoration: none;
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #AAAFEE;
}
div.pagination a:hover, div.pagination a:active {
color: #000;
border: 1px solid #000099;
}
div.pagination span.current {
font-weight: bold;
background-color: #000099;
color: #FFF;
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #000099;
}
div.pagination span.disabled {
color: #DDD;
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #EEE;
}
 Wednesday, October 11, 2006
Base4 & Castle
Well I've been working with HTML & style sheets today (mostly) - It's be a long while since I've done web development, so it was a little tedious, and it did briefly cross my mind that life might be easier if we lived in some kind of dictatorship where style sheets and layout were provided for me by the "man"... at any rate I also managed to fit in a bit of monorail and base4 to keep my brain from freezing over.
I think for this post I might just talk about the way I'm using base4... basically I prototyped some stuff and came to the conclusion that I didn't like the smell of the static StorageContext class in base4 and it's default connection - too hard to test against - not to say that it's a bad idea, just that I couldn't see any easy way to test and mock code for code that used/consumed it... so I decided to work up a simple alternative using castle's IoC and some generic interfaces...
At this point... If you've been using Castle for more then a couple of week this is all old news I'm sure, so probably better off finding something else to read ;o)
The facility
First off we have a facility:
public class Base4StorageFacility : AbstractFacility
{
protected override void Init()
{
string url = FacilityConfig.Attributes["url"];
if (string.IsNullOrEmpty(url))
{
throw new StorageException("The Base4StorageFacility requires a \"url\" attribute to be set");
}
Kernel.AddComponentInstance("base4.defaultContext", typeof (IItemContext), StorageContext.NewContext(url));
Kernel.AddComponent("base4.repository", typeof (IRepository<>), typeof (Base4Repository<>));
}
} A facility extends the container with additional functionality, in this case the only reason we're using a facility (instead of registering the components themselves individually) is because we're using a static method to create our context for a specific base4 connection url. Moving on from here we can register the facility in the containers configuration, incidentally now I have somewhere pleasant to configure what base4 server I connect to by default in my application.
<facility id="base4.storageFacility"
type="MyProject.Core.Base4StorageFacility, MyProject.Core"
url="tcp://Server:@localhost:999/Base4_default" />
The Repository
Now what about the IRepository<> ? well here's the interface:
public interface IRepository<T>
where T : class, IItem, new()
{
IItemListProxy<T> List();
IItemList<T> FindAll();
IItemList<T> Find(ObjectQuery query);
IItemList<T> Find(string path);
IItemList<T> Find(string path, params string[] replaces);
IItemList<T> Find(ObjectPath path);
IItemList<T> Find(ObjectPath path, ObjectScope scope);
IItemList<T> FindUsingSQL(string SQL);
IItemList<T> FindUsingSQL(string SQL, ObjectScope scope);
T Get(T previous);
T Get(object id);
T Get(ItemKey<T> key);
T Get(string relativeUri);
T FindOne(ObjectQuery query);
T FindOne(string opath);
T FindOne(string path, params string[] replaces);
T FindOne(ObjectPath path);
T FindOneUsingSQL(string SQL);
T FindOneUsingSQL(string SQL, ObjectScope scope);
T FindOne(string opath, ObjectScope scope);
T FindOne(ObjectPath path, ObjectScope scope);
void DeleteAll();
void Delete(ObjectPath path);
void Delete(string path);
void Delete(string path, params string[] replaces);
void Delete(T item);
void Save(T item);
T Create(string Xml);
T Create(XmlReader reader);
T Create();
} It's pretty much works like IItemContext, except that you avoid having to pass generic parameters to the individual methods because the interface itself has a generic parameter... there's a couple of extras there that I'll cover at the end of this post too. Conversely, the class Base4Repository<T> implements this interface... which looks like this (or at least the first few methods, I've left the rest out for brevity) - this is similar to what Ivan has done.
public class Base4Repository<T> : IRepository<T>
where T : class, IItem, new()
{
private IItemContext _context;
public Base4Repository(IItemContext context)
{
if (context == null) throw new ArgumentNullException("context");
_context = context;
}
public virtual IItemListProxy<T> List()
{
return _context.List<T>();
}
public virtual IItemList<T> FindAll()
{
return _context.FindAll<T>();
}
Notice that it doesn't have a parameterless constructor, we rely on the container to inject the default IItemContext when creating instances of the Base4Repository...
The Container
Now, by default the container assumes a component has a "singleton" lifestyle, thankfully for a type with a generic parameter it is per that parameter, so this test case below passes - incidentally if you tend to use lifecycles other then the default, I would strongly suggest adding tests to make sure the lifecycle is actually applied... you can just imagine what happens in a multi-threaded app when a "Message" class has a singleton lifecycle when you expected a transient ;o) you end up with some bizarre behavior that might not be picked up in normal unit tests.
[Test]
public void IsSingleton()
{
IRepository<FileBase> fileRepository1 = container.Resolve<IRepository<FileBase>>();
IRepository<FileBase> fileRepository2 = container.Resolve<IRepository<FileBase>>();
Assert.AreSame(fileRepository1, fileRepository2);
IRepository<TypeImpl> typeRepository1 = container.Resolve<IRepository<TypeImpl>>();
IRepository<TypeImpl> typeRepository2 = container.Resolve<IRepository<TypeImpl>>();
Assert.AreSame(typeRepository1, typeRepository2);
} cool, clear as mud? Right... so moving on from there, in my own components when I need to access data I now use the repository... so I could, for instance, create a monorail controller like this:
public class FileController : BaseController
{
private IRepository<FileBase> _repository;
public FileController(IRepository<FileBase> repository)
{
if (repository == null) throw new ArgumentNullException("repository");
_repository = repository;
}
public void Fetch(Guid fileId)
{
CancelLayout();
CancelView(); // very important
Response.Clear(); // ensure the response is empty
FileBase file = _repository.Get(fileId);
if (file != null)
{
Response.ContentType = file.MimeType;
file.FileContent.CopyTo(Response.OutputStream);
}
else
{
Response.StatusCode = 404;
}
}
} And everything will just work - now in some cases this isn't convenient (the dependency injection model) so I broke down and created a static repository class as well, which accesses the default container for the application... basically it has the same interface as IRepository, but they're static methods.. so you can code like this:
Track track = Repository<Track>.Get(id);
Personally I'm not actually that keen on this approach - The Syzmk RMP product I've worked on uses the container everywhere, but avoids ever having to access the default container statically... and if you end up with a class being injected with a large number of dependencies it's often (but not always) a good indication that there's some violation of orthogonality - if only because a class consuming that many dependencies is probably doing more then one thing... a little difficult to pick up on otherwise.
But at any rate It seems pretty good for a website, where I can't see me using more the one container (or even child containers) within the same app domain.
Wrinkles...
Moving beyond that, the last thing I have to say is that originally I was creating new instances and then saving them with a repository like this:
Group group = new Group();
... Repository<Group>.Save(group);
...
User user = new User();
... user.Groups.Add(group);
... Repository<User>.Save(user); However, it all turns to 4 shades of brown when we go to add to a many-to-many collection, like this:
Goat goat = new Goat();
goat.Name = "junk";
Repository<Goat>.Save(goat);
BoatOfGoats boat = new BoatOfGoats();
boat.Name = "track";
boat.Goats.Add(goat); // <-- "StorageException : Default is not available, as no default has been set"
Repository<BoatOfGoats>.Save(track); As far as I can tell the event handling for the Add(item) method expects a default context to be assigned... now I'd be tempted to call this a bug, but that's a bit rash till I understand the in's and out's of base4, however there's an easy way round it... and that's to assign the context yourself :) so a fix would be to add this line before the one that bombs:
track.Context = container.Resolve<IItemContext>(); But that's pretty kludgey, so instead of using:
I added some Create(...) overloads to the repository to take care of it... and do this:
Genre genre = Repository<Genre>.Create();
Last of all, though I haven't drawn on the entire implementation, I'm hoping to follow (At least in spirit) some of the work Ayende has done with his NHibernate repository concept as the project progresses, I think it will add a more natural "feel" combined with the repositories for implementing transactions vs. interacting with base4's ObjectTransaction directly, not to mention providing something I can test and mock out easily... We shall see what actually happens as the project progresses.
 Sunday, October 08, 2006
Well, I've started working with the latest drop of Base4.net ( version 2.1) - in fact I've decided to take the plunge and actually start using it for the project I'm currently working on (a work project, rather then a home project) so I should be giving it a pretty good thrashing over the next 3-6 months. I already had a rough schema in place, so I generated types from it using the bundled web admin... It seems pretty cool... though I've struck a few things:
- nvarchar(256) fields seems to show up as being 512 characters in length within base4.net... I'm not sure if this is a bug with the schema interrogation, guess we'll find out as a I dig further in ;o) - though it's only skin deep of course, as you can change them to 256 with a quick edit.
- I managed to create an assembly that was invalid... not sure how ;o) I could look at in reflector .Net, but base4 wasn't having a bar of it (even though it had generated it) - I must have screwed up a relationship somewhere, but I wasn't really sure... ended up just dumping it and starting from scratch again.
- It doesn't seem that easy to refactor existing schema's using the web designer... while I was learning it would have been good to generate a schema, play with the assembly, then start editing and generate again... instead I ended up having to save the schema to disk, delete, edit, and recreate. Still, it's pretty slick :)
I think though it probably all comes down to:
- My urge to make things happen without understanding the in's and outs of base4.net
- Horses for courses, the web admin is great for getting off to ground with base4.net, but I think I'll have to get down and dirty with the xml pretty soon...
Though I can't discuss the project, I can discuss what I'll be building it in... so we have:
- Base4.Net
- SQL 2005
- Castle (Monorail & IoC)
- NLog (or log4net... though I'm loosing faith in the latter)
- NUnit
- RhinoMocks
- Splicer.Net
- Some COM & Unmanaged code for audio processing
This is also the first time I've used monorail for a commercial project (we already use a lot of the facilities and the windsor container in the Syzmk RMP product) so it's certainly some interesting times... as we progress I'll give some feedback on both the Monorail and Base4.Net "user experience" :)
The sourcode for the previous post (Integrating NUnit & IronPython...)
Integrating NUnit & IronPython....
 Wednesday, October 04, 2006
Well, Seo Sanghyeon asked me a pretty reasonable question of the last entry
"Why don't you use help(), instead of printing Overloads?"
Good question, I didn't realise that actually worked in IronPython for
.Net types, I was very pleasantly surprised, I remember in the early
betas i tried using help() on various managed types and it would just raise a
NotImplementedException exception (or something like that, I forget
now) - so what does that mean for my examples... well... let's take a
system type like Guid and use help() on it.
IronPython 1.0.60816 on .NET 2.0.50727.42
Copyright (c) Microsoft Corporation. All rights reserved.
>>> import System
>>> from System import *
>>> help(Guid)
Help on Guid in module System in mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
| Guid(Array[Byte] b)
| Guid(UInt32 a, UInt16 b, UInt16
c, Byte d, Byte e, Byte f, Byte g, Byteh, Byte i, Byte j, Byte k)
| Guid(str g)
| Guid(int a, Int16 b, Int16 c, Array[Byte] d)
| Guid(int a, Int16 b, Int16 c,
Byte d, Byte e, Byte f, Byte g, Byte h, Byte i, Byte j, Byte k)
| Guid CreateInstance[Guid]()
|
| Data and other attributes defined here:
|
| CompareTo(...)
| int CompareTo(self, object value)
| int CompareTo(self, Guid value)
| Equals(...)
| bool Equals(self, object o)
| bool Equals(self, Guid g)
| Finalize(...)
| Finalize(self)
| GetHashCode(...)
| int GetHashCode(self)
| GetType(...)
| Type GetType(self)
| MemberwiseClone(...)
| object MemberwiseClone(self)
| NewGuid(...)
| Guid NewGuid()
| ToByteArray(...)
| Array[Byte] ToByteArray(self)
| ToString(...)
| str ToString(self)
| str ToString(self, str format)
|
str ToString(self, str format, IFormatProvider provider)
| __eq__(...)
| bool op_Equality(Guid a, Guid b)
| __init__(...)
|
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
|
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
| __ne__(...)
| bool op_Inequality(Guid a, Guid b)
| __new__(...)
| __new__(cls, Array[Byte] b)
|
__new__(cls, UInt32 a, UInt16 b, UInt16 c, Byte d, Byte e, Bytef, Byte
g, Byte h, Byte i, Byte j, Byte k)
| __new__(cls, str g)
|
__new__(cls, int a, Int16 b, Int16 c, Array[Byte] d)
|
__new__(cls, int a, Int16 b, Int16 c, Byte d, Byte e, Byte f, Byte g,
Byte h, Byte i, Byte j, Byte k)
| Guid CreateInstance[Guid]()
|
>>>
Sweet, it works a treat - and will save a lot of digging time - though you might want to capture the results for big classes ;o)
Thanks Seo!
(btw, Seo is the man behind the Iron Python Community Edition & FePy projects - which can be found on sourceforge) and I would have to agree with this article that he does seem almost OmniPresent in the IronPython community...
This entry was going to cover thinking about your .Net
classes from the perspective of Python consumption… but actually it's
not, we'll cover that another time. What this post is really
going to be about is how to spelunk a little into our managed classes
via the IronPython interactive console - and to see how some common
practices in .Net have interesting results in python. This
entry is going to be a little slow paced, I’m making the assumption
you’re a .Net developer, and haven’t cut Python code before, if you
know your way around Python probably best to pass this one over. Also worth noting at this point that I'm really just a Python hacker, and certainly no guru... So
first off, we have a class with a bunch of overloads for various
methods, here is the interface… I’ve left the code for the class itself
out, but the class is called MyFileStore.
public interface IMyFileStore { Guid AddFile(string fileName); Guid AddFile(string fileName, string mimeType); Guid AddFile(byte[] contents, string mimeType); Guid[] AddFiles(params string[] fileNames); Guid AddFile(byte[] contents); byte[] ReadFile(Guid id, out string mimeType); void ReadFile(Guid id, string fileName); void ExtractFiles(ref IList<byte[]> myList); } Pretty simple, now lets look at using this class with Iron python, I’ll be running with the ipy
(the interactive interpreter) so we can investigate our types as we go
along (this is an executable which comes with the Iron Python
binaries). The ipy console has a prompt consisting of three
greater then signs “>>>” so you’ll know what I’m typing into
the console by looking for those. First off, we need to load our type… this is pretty trivial… >>> import clr >>> clr.AddReferenceToFileAndPath("D:\\Demo\\SampleIronPythonLib.dll") >>> from IronPythonLib import * All
done, lets make sure our class is in there, using the inbuilt function
dir() – a list of built-in functions can be found here: http://www.python.net/quick-ref1_52.html#BuiltIn >>> dir() ['IMyFileStore', 'MyFileStore', '_', '__builtins__', '__doc__', '__name__', 'clr', 'results', 'site', 'store', 'sys'] MyFileStore, sweet. First off, lets create an instance of my type (not yours ;o) >>> store = new MyFileStore() Traceback (most recent call last): SyntaxError: unexpected token MyFileStore (<stdin>, line 1) >>> Arse, python doesn’t have a new operator… forgot that, lets try it again. >>> store = MyFileStore Right,
looks good, interpreter didn’t return any errors… but wait, lets make
sure we got what we want, which is an instance of MyFileStore…. >>> store <type ‘MyFileStore’> >>> Woops, that’s not what we wanted, we want an instance, not the type… lets try again: >>> store = MyFileStore() >>> store <MyFileStore object at 0x0000000000000035> >>> That’s better, lets find out what our store is capable off, using the dir command. >>> dir(store) ['AddFile',
'AddFiles', 'Equals', 'ExtractFiles', 'Finalize', 'GetHashCode',
'GetType', 'MakeDynamicType', 'MemberwiseClone', 'ReadFile', 'Reduce',
'ReferenceEquals', 'ToString', '__class__', '__doc__', '__init__',
'__module__', '__new__','__reduce__', '__reduce_ex__', '__repr__'] >>> We
see our AddFile, AddFiles,ReadFile & ExtractFiles methods –
everything looks to be in order… but what are the parameters for those
methods? >>> dir(store.AddFile) ['Call', 'CallInstance', 'Equals', 'Finalize', 'GetHashCode', 'GetTargetType', ' GetType',
'Make', 'MakeDelegate', 'MakeDynamicType', 'MemberwiseClone',
'Overloads', 'PrependInstance', 'Reduce', 'ReferenceEquals',
'ToString', '__call__', '__class__', '__doc__', '__eq__',
'__getitem__', '__hash__', '__init__', '__module__', '__name__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__',
'__str__'] >>> Hmm… what’s the “Overloads” thing, lets find out… >>> dir(store.AddFile.Overloads) ['Equals',
'Finalize', 'Function', 'GetHashCode', 'GetOverload',
'GetTargetFunction', 'GetType', 'MakeDynamicType', 'MemberwiseClone',
'Reduce', 'ReferenceEquals', 'Targets', 'ToString', '__class__',
'__doc__', '__getitem__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__str__'] >>> That doesn’t seem very useful, though what if we check it’s string representation? >>> store.AddFile.Overloads <IronPython.Runtime.Calls.BuiltinFunctionOverloadMapper
object at 0x0000000000000036 [{'Guid AddFile(self, str fileName)':
<built-in function AddFile>, 'Guid AddFile(self, str fileName,
str mimeType)': <built-in function AddFile>, 'Guid AddFile(self,
Array[Byte] contents, str mimeType)': <built-in function
AddFile>, 'Guid AddFile(self, Array[Byte] contents)': <built-in
function AddFile>}]> >>> Look at that, there are our 4 overloads – but it’s a bit jumbled, what am I looking at it…. Well
at first glance it looks a bit like a python dictionary… notice the
colon separating the signature for the method and <built-in function
AddFile> … what if we try to grab one for use later, maybe for some
functional programming, why don’t we get the one which takes the
fileName and mimeType parameters eh? >>> myFunc = store.AddFile.Overloads[str,str] Traceback (most recent call last): File , line 0, in <stdin>##100 TypeError: __getitem__() takes exactly 1 argument (1 given) >>> Bugger,
that didn’t work… still, not a bad guess - one parameter eh? Lets have
another stab, maybe it just wants us to group the types together
somehow? >>> myFunc = store.AddFile.Overloads[(str,str)] >>> myFunc <built-in method AddFile of MyFileStore object at 0x0000000000000035> >>> Looks better, of course if we wanted to we could use our function right now… let’s give it a whirl: >>> myFunc("d:\\testinput.3gp", "video/3gpp") <System.Guid object at 0x0000000000000037 [7b6d6dc5-bbe6-4831-bff7-21984031684f]> >>> Looks
to have worked, the method has successfully returned us a Guid
identifying the new file… shame we didn’t save it into a variable for
future reference, cest la vie. Luckily I can just copy and paste it – lets see if I can get the file back using this overload… byte[] ReadFile(Guid id, out string mimeType); Simple as.. lets try… >>> id = Guid("7b6d6dc5-bbe6-4831-bff7-21984031684f") Traceback (most recent call last): File , line 0, in <stdin>##116 NameError: name 'Guid' not defined >>> Woops, we need to import the System namespace… >>> import System Now lets try again… >>> id = Guid("7b6d6dc5-bbe6-4831-bff7-21984031684f") Traceback (most recent call last): File , line 0, in <stdin>##116 NameError: name 'Guid' not defined >>> Huh… oh wait, let’s check our local symbol table: >>> dir() ['MyFileStore',
'System', '_', '__builtins__', '__doc__', '__name__', 'clr', 'myArray',
'myFunc', 'results', 'site', 'store', 'sys'] System eh? Lets dig into it… >>> dir(System) ['AccessViolationException', 'Action', 'ActivationContext', 'Activator', 'AppDom ain', 'AppDomainInitializer', 'AppDomainManager', 'AppDomainManagerInitializatio nOptions', 'AppDomainSetup', 'AppDomainUnloadedException', 'ApplicationException… and all the rest. >> Well,
what can we do about that… we could import them all using “from System
import *” – but we only need Guid, so why don’t we just grab that eh? >>> from System import Guid >>> dir() ['Guid',
'MyFileStore', 'System', '_', '__builtins__', '__doc__', '__name__',
'clr', 'myArray', 'myFunc', 'results', 'site', 'store', 'sys'] >>> Sweet, now lets try it again… finally! >>> id = Guid("7b6d6dc5-bbe6-4831-bff7-21984031684f") >>> mimeType = "" >>> contents = store.ReadFile(id, mimeType) Traceback (most recent call last): File , line 0, in <stdin>##136 File , line 0, in ReadFile##66 File D:\dev\Projects\IronPythonDemo\IronPythonLib\MyClass.cs, line 70, in Read File File mscorlib, line unknown, in WriteAllBytes File mscorlib, line unknown, in .ctor File mscorlib, line unknown, in Init ValueError: Empty path name is not legal. >>> Oh
no! what went wrong??… what’s this about an empty path name, I was
expecting to get some bytes back…. Hmmm, don’t panic, lets just do some
digging… >>> store.ReadFile.Overloads <IronPython.Runtime.Calls.BuiltinFunctionOverloadMapper
object at 0x0000000000000039 [{'(Array[Byte], str) ReadFile(self, Guid
id)': <built-in function ReadFile>, 'ReadFile(self, Guid id, str
fileName)': <built-in function ReadFile>}]> >>> Well
there’s the problem, I’ve called the wrong version, but… that’s odd,
there’s a ReadFile there I haven’t defined in my class… and one that’s
missing… hmmm, time to file a bug report. Or not, this is just where the Python and .Net world don’t see eye to eye – Python doesn’t know about out
parameters as such, so it simulates the effect by altering the method’s
signature – lets have a go at playing by IronPython's rules: >>> contentsAndMimeType = store.ReadFile(id) >>> len(contentsAndMimeType) 2 >>> type(contentsAndMimeType[0]) <type 'Array[Byte]'> >>> type(contentsAndMimeType[1]) <type 'str'> >>> contentsAndMimeType[1] 'video/3gpp' >>> So our “out string mimeType” parameter was returned by the method instead, as the second item in an array… hmm… interesting. Well
if python does this to out parameters, what does it do to ref
parameters – lets try the extract files method to see what happens…
this method is implemented to create a new list if we don’t supply a
valid instance, but lets pass in a valid one first – I wont be caught
out this time, so I’ll import the types I need first (List<T>): >>> from System.Collections.Generic import * >>> bytes = List<byte[]>() Traceback (most recent call last): SyntaxError: unexpected token ] (<stdin>, line 1) >>> Oh dear, looks like Python doesn’t use the <T> syntax… lets start digging again… >>> dir(List) ['Add', 'AddRange', 'AsReadOnly', 'BinarySearch', 'Capacity', 'Clear', 'Contains ', 'ConvertAll', 'CopyTo', 'Count', 'Enumerator', 'Equals', 'Exists', 'Finalize' , 'Find', 'FindAll', 'FindIndex', 'FindLast', 'FindLastIndex', 'ForEach', 'GetEn umerator',
'GetHashCode', 'GetRange', 'GetType', 'IndexOf', 'Insert',
'InsertRange', 'LastIndexOf', 'MakeDynamicType', 'MemberwiseClone',
'Reduce', 'ReferenceEquals', 'Remove', 'RemoveAll', 'RemoveAt',
'RemoveRange', 'Reverse', 'Sort', 'ToArray', 'ToString', 'TrimExcess',
'TrueForAll', '__class__', '__doc__', '__getitem__', '__init__',
'__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setitem__'] >>> List <type 'List[T]'> >>> Hmm… nothing obvious there, but we could hazard a guess… >>> List[str] <type 'List[str]'> >>> Hmmm… so lets give our List of byte array another go… >>> bytes = List[byte[]]() Traceback (most recent call last): SyntaxError: unexpected token ] (<stdin>, line 1) Hmm… it doesn’t like byte, lets have a look… >>> byte Traceback (most recent call last): File , line 0, in <stdin>##56 NameError: name 'byte' not defined >>> Byte <type 'Byte'> >>> Ahhh…
I forgot that “byte” (lowercase) isn’t actually what the Clr calls it…
hmm… we could try it again, but it wont work – simply because Byte[]
doesn’t make sense (if we’re using square brackets to index into a
generic type… ) so having another dig in the IronPython docs we see
that we need to index to the type “Array” with the type of our array,
given this knowledge we can get what we want… >>> bytes = List[Array[Byte]]() >>> bytes <List[Array[Byte]] object at 0x000000000000002C> >>> Sweet, now to call that ExtractFiles method… >>> store.ExtractFiles(bytes) <List[Array[Byte]] object at 0x000000000000002C> >>> bytes <List[Array[Byte]] object at 0x000000000000002C> >>> len(bytes) 8 Well
it returned a list… but it did accept our reference parameter, and it
has updated the collection we passed to it… but what if we had passed
it a null instead? >>> bytes = None >>> store.ExtractFiles(bytes) <List[Array[Byte]] object at 0x0000000000000030> >>> len(bytes) Traceback (most recent call last): File , line 0, in <stdin>##83 File , line 0, in Length##75 TypeError: len() of unsized object of type <type 'NoneType'> >>> Hmmm… it returned a list, but it didn’t set the value in our variable "bytes" – this isn’t really ref like behavior… yet, if you think about it we can get almost the same thing by doing this: >>> bytes = store.ExtractFiles(bytes) >>> len(bytes) 8 >>> Right, our journey has almost come to an end… looking at the interface we have a method declared like so: Guid[] AddFiles(params string[] fileNames); params
is handy in .Net code – anything to save tedious typing of array
declarations, lets see if we can do the same thing in python? >>> store.AddFiles("d:\\testinput1.3gp", "d:\\testinput2.3gp") System.Guid[](<System.Guid
object at 0x0000000000000031
[d3e8f099-3005-461c-a63a-fdc69b2091ee]>, <System.Guid object at
0x0000000000000032 [d9d1fb25-fc7a-47a2-89ac-c11264bfa47f]>) >>> Sweet, that’s a pleasant surprise after that whole out and ref debacle, I was beginning to loosing hope! But wait, why not revive our faith in Python a little more by looking at a few tricks… >>> paramsDict = { "fileName" : "d:\\testinput.3gp", "mimeType" : "video/3gpp"} >>> store.AddFile(**paramsDict) <System.Guid object at 0x0000000000000033 [e07680d9-f544-4847-9a1e-d04a0ef137f7]> >>> What
did we just do? Well… given a dictionary, where the keys are the
parameter names, we used them as the parameters for one of our .Net
methods using the double asterisk syntax – think of what you’d
have to do to code this in .Net… reflection city ;o) It doesn’t just have to be dictionaries… we can use arrays too… >>> paramsArray = [ "d:\\testinput.3gp", "video/3gpp" ] >>> store.AddFile(*paramsArray) <System.Guid object at 0x0000000000000034 [85006c43-e6f5-4e90-b837-0868788cf453]> >>> Neat,
of course, being a dynamic language and all, the selection of the
appropriate overload is based on the types in the array or dictionary…
it would be a nightmare to do both of these in .Net with reflection
yourself. Faith still not restored eh, what about creating a
python class that wraps an existing (possibly sealed) .Net class, that
forwards calls on unless we want to override the behavior… >>> class MyFileStoreWrapper: ... def __init__(self, realStore): ... self.realStore = realStore ... def ExtractFiles(self, myList): ... raise Exception, "this method isn't allowed" ... def __getattr__(self, name): ... if name == "ExtractFiles": return ExtractFiles ... return eval("self.realStore."+name) ... >>> store = MyFileStoreWrapper(MyFileStore()) >>> store.AddFile("d:\\testinput.3gp") <System.Guid object at 0x000000000000002C [a2bf8747-cc71-4b79-8c02-0b61a87ff67f] > >>> store.ExtractFiles(None) Traceback (most recent call last): File , line 0, in <stdin>##52 File , line 0, in ExtractFiles Exception: this method isn't allowed >>> ExtractFiles
can’t be invoked on our wrapper, however our wrapper automagically
responds for other methods like AddFile – sadly I’ve used an eval (which,
rhymes with Evil - coincidence?) here because MyFileStore doesn’t
expose a __getattr__ method (because it's a .Net classes, not a
native Python one). The nice thing now, is that given a native
python class, we can do some things we aren’t allowed to do to the
underlying .Net class – like adding new methods at run time. >>> def ExtractMoreFiles(self, myList): ... raise Exception, 'not implemented yet' ... >>> MyFileStoreWrapper.ExtractMoreFiles = ExtractMoreFiles >>> store.ExtractMoreFiles(None) Traceback (most recent call last): File , line 0, in <stdin>##60 File , line 0, in ExtractMoreFiles Exception: not implemented yet >>> I
think it’s pretty cool, and though python's metaprogramming model isn’t
quite up to ruby standards, it’s still pretty easy to dig down and
create some pleasantly surprising results :) and if you have your
thinking caps on you can probably see how this stuff would really help
to bring a DSL to life for your applications special needs. And
that’s where I’m going to conclude this rambling post…
;o) Hopefully it'll spark some thoughts about what's possible with
IronPython and allow you avoid some simple mistakes when using .Net
classes in iron python.
 Tuesday, October 03, 2006
Secnd alpha of Splcer released - version 0.9.1.7304
 Sunday, October 01, 2006
Back once more...
I decided to spend ten minutes implementing a
version of the last post which didn't require us to generate a function
definition for a python method with a generic number of parameters... it's actually not too hard.
First off, the key to solving this problem is to generate a Type for
our custom delegate - for performance reasons you would want
to cache the results, but we won't do that here... Also I think it would
be more apropriate for the first 0->9 parameters that we just return
a generic Func delegate (generic Func & Proc delegates are going to
be part of .Net 3.0, as mentioned here - At the moment I use something similar from the RhinoCommons library, have a look here)
So, first off we build a helper method for generating our delegate - just heavy use of emit here, based off an example on MSDN:
public Type CreateCustomDelegate(Type returnType, params Type[] parameterTypes)
{
AssemblyName assembly = new AssemblyName();
assembly.Name = "CreateCustomDelegateAssembly";
AssemblyBuilder assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("TempModule");
TypeBuilder typeBuilder =
moduleBuilder.DefineType("TempDelegateType",
TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class |
TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof (MulticastDelegate));
ConstructorBuilder constructorBuilder =
typeBuilder.DefineConstructor(
MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public,
CallingConventions.Standard, new Type[] {typeof (object), typeof (int)});
constructorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
MethodBuilder methodBuilder =
typeBuilder.DefineMethod("Invoke",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot |
MethodAttributes.Virtual, returnType, parameterTypes);
methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime);
return typeBuilder.CreateType();
}
Basically it goes through the motions of building a delegate type, derived from MulticastDelegate with our selected output type and parameter types...
Now to put that type to use:
[Test]
public void WithCustomDelegate()
{
Dictionary<string, object> context = new Dictionary<string, object>();
context.Add("user", "alex");
context.Add("age", 26);
Proc testCore = delegate
{
List<string> parameters = new List<string>(context.Keys);
List<object> values = new List<object>(context.Values);
PythonEngine engine = new PythonEngine();
Type[] parameterTypes = new Type[context.Count];
for (int i = 0; i < parameterTypes.Length; i++) parameterTypes[i] = typeof (object);
Type delegateType = CreateCustomDelegate(typeof (object), parameterTypes);
Type pythonEngine = typeof (PythonEngine);
MethodInfo genericMethod =
pythonEngine.GetMethod("CreateMethod", new Type[] {typeof (string), typeof (IList<string>)});
MethodInfo method = genericMethod.MakeGenericMethod(delegateType);
object result =
method.Invoke(engine,
new object[] {"return user + ' is ' + str(age) + ' years old'", parameters});
Delegate myDelegate = (Delegate) result;
Assert.AreEqual("alex is 26 years old", myDelegate.DynamicInvoke(values.ToArray()));
};
// try it with our two keys in the dictionary
testCore();
// try it with another key in the dictionary
context.Add("monkey_colour", "brown");
testCore();
}
Our test creates our custom delegate type for the number of parameters we have, and then we use that when invoking the PythonEngine.CreateMethod<TDelegate>(string statements, IList<string> parameters) method.
Here we have to do a little reflection, simply because we cant directly
use a local variable of type "Type" as a generic type parameter, so we
grab the generic method, set the parameter and then invoke it.
However in the end, as you can see we get a real Delegate, which we can use DynamicInvoke upon.
This is actually pretty handy, and it's certainly a lot more
script-friendly, compared to the alternative of forcing users to look
up values from context by index ie.
context['user'] + ' is ' + str(context['age']) + ' years old'
vs.
user + ' is ' + str(age) + ' years old'
I know what I prefer ;o)
 Saturday, September 30, 2006
Part 2 - More IronPython and delegates…
So we have briefly covererd strongly typed delegates and event
handlers... But they make the assumption that we know what our
arguments are at compile time, what if we dont?
Say for instance you're expression engine has a bag of contextual values being passed around in a dictionary, like this:
Dictionary<string, object> context = new Dictionary<string, object>();
context.Add("user", "alex");
context.Add("age", 26);
What if we want to use python to evaluate expressions against that
context?... Say something like writing out “my name is alex and my age
is 25" - the expression in python is easy enough, we can go:
‘my name is’ + name + ‘ and my age is ‘ + str(age)
But how do we marry all these together... lets start exploring... ever noticed that delegates have a DynamicInvoke method with a signature like this?
object
DynamicInvoke(params object[] parameters)
Perhaps we can try and use this to our advantage... lets see shall we?
First Attempt
[Test]
[ExpectedException(typeof (ArgumentException), "T must be a concrete delegate, not MulticastDelegate or Delegate")]
public void LooseDelegateAndDynamicInvoke()
{
PythonEngine engine = new PythonEngine();
List<string> parameters = new List<string>(new string[] {"name", "age"});
Delegate func =
engine.CreateMethod<Delegate>("return ‘my name is’ + name + ‘ and my age is ‘ + str(age)", parameters);
string result = (string) func.DynamicInvoke("alex", 26);
Assert.AreEqual("my name is alex and my age is 25", result);
}
Sadly this doesn’t work so well, seems the PythonEngine is looking for
a concrete delegate... we could try giving it void delegate,
but it does type checking on the number of parameters and their type,
so we're a little stuck.
At this point I think the best answer is to actually build some code
which generates the apropriate delegate type, based on the supplied
dictionary, and then passing that onto the python engine, but there is
another way… it’s a little less elegant, but it’s at least amusing:
Round 2
First of let’s build a little helper method...
private static string GenerateFunction(string functionName, string[] parameters, string statements)
{
StringBuilder builder = new StringBuilder();
builder.AppendFormat("def {0}(", functionName);
for (int i = 0; i < parameters.Length; i++)
{
if (i > 0) builder.AppendFormat(", ");
builder.AppendFormat(parameters[i]);
}
builder.AppendFormat("):\r\n ");
builder.AppendFormat(statements.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "\r\n "));
return builder.ToString();
}
You can no doubt see where this is going – so given a statement like this:
GenerateFunction("func", new string[] { "user", "age" }, "return user + ' is ' + str(age) + ' years old'")
We’d end up with a string like this:
def func(user, age):
return user + ' is ' + str(age) + ' years old'
And, moving on from there we build a test…
[Test]
public void GeneratingPythonFunction()
{
Dictionary<string, object> context = new Dictionary<string, object>();
context.Add("user", "alex");
context.Add("age", 26);
List<string> parameters = new List<string>(context.Keys);
List<object> values = new List<object>(context.Values);
PythonEngine engine = new PythonEngine();
engine.Execute(
GenerateFunction("func", parameters.ToArray(), "return user + ' is ' + str(age) + ' years old'"));
PythonFunction func1 = engine.EvaluateAs<PythonFunction>("func");
engine.Execute(
GenerateFunction("func", parameters.ToArray(),
"return user + ' is ' + str(age+1) + ' years old next year'"));
PythonFunction func2 = engine.EvaluateAs<PythonFunction>("func");
object result1 = func1.Call(values.ToArray());
Assert.AreEqual("alex is 26 years old", result1);
object result2 = func2.Call(values.ToArray());
Assert.AreEqual("alex is 27 years old next year", result2);
}
Are there problems with this?… well there’s a few, unsurprisingly!
• PythonFunction’s are not delegates.
• String manipulation is a bit clunky
• Because these are named functions, you probably
want to lock against some object when generating the function, to avoid
cross-threading issues…
Back to delegates
Aside from the problems it works alright, but what we really want is a
delegate… those PythonFunctions don’t give you the flexibility to
substitute IronRuby in the future now do they?
So first off, lets
declare a delegate suitable for our purposes.
[ThereBeDragons("Only use as a last resort")]
public delegate object UntypedDelegate(params object[] parameters);
Aint she a beauty ;o) - full credit for the ThereBeDragons attribute goes to Ayende,
though it's probably not really warranted in this situation - now,
let’s rework the last test to use a delegate instead, a simple
anonymous delegate will do the dirty work:
[Test]
public void UntypedDelegateForPythonFunction()
{
Dictionary<string, object> context = new Dictionary<string, object>();
context.Add("user", "alex");
context.Add("age", 26);
List<string> parameters = new List<string>(context.Keys);
List<object> values = new List<object>(context.Values);
PythonEngine engine = new PythonEngine();
engine.Execute(GenerateFunction("func",parameters.ToArray(),"return user + ' is ' + str(age) + ' years old'"));
PythonFunction func1 = engine.EvaluateAs<PythonFunction>("func");
UntypedDelegate func1Delegate = delegate(object[] param)
{
return func1.Call(param);
};
object result1 = func1Delegate(values.ToArray());
Assert.AreEqual("alex is 26 years old", result1);
}
It’s certainly better then passing around PythonFunction instances –
though you need to be a little careful… there’s a little quirk here, if
we were to use:
object result1 = func1Delegate.DynamicInvoke(values.ToArray());
It’s going to fail because the wrong number of arguments were supplied
(it expects only 1, an array), so our delegate doesn’t really behave
like it has multiple parameters.. so to dynamically invoke this
delegate we’d need to take special care, promoting the arguments into a
second array like so:
object result1 = func1Delegate.DynamicInvoke(new object[] { values.ToArray()});
Next Time
When I get bored I'll write a version which doesn't require the clunky generator and post it up...
Next time I'll talk about writing classes which are python-friendly, riveting stuff eh? As you were.
I felt like posting some code snippets… so I was looking around and
thought
perhaps some IronPython might be interesting…. Some of you may find
this useful, possibly not. I tend to explore functionality using
unit tests, so all my code will be test cases – I might make this part
of a small series on looking at python code with a view to integrating
it into an existing system as a scripting engine. Lets call the
series "IronPython is your friend"... because it really is.
Part 1 - IronPython and delegates….
So you have downloaded the IronPython runtime dll's, and you would like
to start integrating it into some project your working on… first off
lets create a python engine, and make sure it goes….
[Test]
public void GetGoing()
{
PythonEngine engine = new PythonEngine();
engine.Execute("myString = 'hello'");
Assert.AreEqual("hello reader", engine.Evaluate("myString + ' reader'"));
}
That was pretty easy; we executed some python code to assign the value
hello to myString, and then evaluated the expression – sweet you might
say – no effort required.
Now, you could write your scripting engine so that it passed the
strings to the engine for evaluation every time you wanted to evaluate
them – but this strings malarkey isn’t very pleasant… what we really
want is a decent god fearing .Net delegate, so we can call this without
having to think about the python engine…. Lets check out our first
destination, method delegates.
Method Delegates
Given a converter delegate like this:
Converter<int, string>
(Which by the way, if you haven’t stumbled across the generic
Converter<TInput,TOutput> delegate yet, effectively you end up
with a delegate method of the definition“TOutput Converter(TInput)” – pretty handy
actually)
We could do this:
[Test]
public void StatementsToStronglyTypedDelegate()
{
PythonEngine engine = new PythonEngine();
List<string> parameters = new List<string>(new string[] {"age"});
Converter<int, string> converter =
engine.CreateMethod<Converter<int, string>>("return str(age+1)", parameters);
Assert.AreEqual("11", converter(10));
}
Using a strongly typed overload for the engine's CreateMethod method,
we’re able to evaluate statements using our new delegate, which in turn
uses our IronPython method we created earlier… looks promising!
Events
Now delegates are cool, but it’s only half the story for
scripting in an application – depending on your model, you may be
aiming to produce results similar to a microsoft’s VBA in applications like Excel or Word – and for this
we need to be able to assign python code to events on our own classes…
we can do this using delegates of course, or we could let the python (user code)
do this itself, and save some time…. So lets have a look at the latter:
[Test]
public void HookingToEvents()
{
PythonEngine engine = new PythonEngine();
ManualResetEvent waitHandle = new ManualResetEvent(false);
WebClient client = new WebClient();
List<string> results = new List<string>();
engine.Globals["client"] = client;
engine.Globals["results"] = results;
engine.Execute(
@"def storeResult(sender, e):
results.Add(e.Result)
e.UserState.Set()
# assign out storeResult function as an event handler for the client class
client.DownloadStringCompleted += storeResult
");
client.DownloadStringAsync(
new Uri(
"http://api.feedburner.com/awareness/1.0/GetFeedData?uri=http://feeds.feedburner.com/BitterCoder"),
waitHandle);
Assert.IsTrue(waitHandle.WaitOne(10000, false), "timeout occured after 10 seconds");
Assert.AreEqual(1, results.Count);
Assert.IsTrue(results[0].StartsWith("<?xml"));
}
This test is a bit clunky, but you get the idea… we are:
- Creating a web client, for downloading some xml from a web site.
- Set the client as a global variable for the default module in the python engine.
- Execute some python, which creates a function, and assigns that
function as a handle for the web client's DownloadStringCompleted event
(take note at how concise the code is, this would be a lot uglier in C#)
- start the async download
- Make sure we got a response, and that the python code did what it should.
All in all, with a little finesse you can recreate a model similar to
VBA, driving your extension points from events – and this certainly has
some merit – obviously you want to create the code in their own
modules, as opposed to using the default module for the python engine
as we are.
We haven't quite finished with delegates yet though, I'll leave that for part 2 - which I'll post shortly.
 Wednesday, September 27, 2006
A quick look at batching support, which seems to be creeping into data access code lately ;o)
Over the past couple of days I've been working on using
DirectShow and DES (DirectShow Editing Services) for re-encoding mobile
video content suitable for posting on the web... With the goal of
including video editing into our unified "media engine" which the Syzmk
line of products makes use of... as an off-shoot of that work I decided
to refactor the rather ugly code we had for working with DES over the
weekend into something a little less ugly, that hid most of the details
away, say hello to:
(sorry, couldn't resist the lame web 2.0 logo ;o)
A simple little library for doing most of the useful things in DES, the project is hosted here up on Codeplex.
It's currently in an alpha state, at version 0.9.0.0 - and should get
feature drops every week or so until I think it can go into beta.
To give an idea of what I'm up to, it's basically just wrapping up the
various DES components and removing alot of the unpleasantness (ie. you
get to deal with human-friendly units of time like seconds) .. and
seperating the concerns of the timeline, and rendering that timeline
into something useful like audio or video container (currently that's
just WAV, AVI & Windows Media formats). It's fully
functional, but the interfaces at this point it isn't very stable as
I'm likely to refactor the various interfaces mercilessly till I get it
working how I want, so if you build something with the library now,
it's likely to break in the future (but probably not in major way, it
is after all mirroring the functionality available in DES).
The added bonus of developing a set of rich wrappers for a lot of this
stuff is that I can mock away the requirement on DES altogether, which
is always a bonus considering how long the units tests currently take
to run for the Syzmk RMP product.
When I get a chance, I'll put up some code examples to demonstrate how
you might use it... At any rate it'll be going through some dog fooding
in the next month or so while I integrate it with the Syzmk product, so
you'll probably here a little more about in the future.
After a long hiatus from Blogging, I've returned... hopefully
with a vengence, but more likely with a small "vurrrrp" sound... like
hot air bubbling up through porridge.
Lets start off with a recap... Spectacles, testacles, wallet and all that jazz.
My name is Alex Henderson, 26 years young, living in Auckland, New
Zealand. I've been working on code since I was knee high, cut my
teeth in GW Basic while in primary school, and C++ a few years after
that... Now days I tend to spend my hours working in C# code, and my
spare time in either .Net and ruby or python when I feel like a change.
For the last year and a half I've been working for a start up company called Seismic Technologies which works in a rather ill-defined space, which I'll probably talk about in posts to come.
The main product I've been working on for Syzmk is the " Rich Media
Processor" - it's a message clearing house, geared towards taking
messages with rich content, transforming them, and then distributing
them... The messages might be files on a network share, emails, SMS or
MMS messages from a phone etc. It's all about rich content, so a
large part of the product deals with transforming the content before
furnishing it to line of business systems - we have been working with
companies like XSOL who use our product to use messages from mobile devices to extend their business processes outside of the host organisation.
Before I was working for the Seismic, I was travelling around Asia for
4 months... which was a lot of fun, I hope to visit europe next... Then
maybe Japan, Egypt and South America.
 Wednesday, April 05, 2006
With the first release of our COM interop SDK for the Syzmk Rich
Media Processor (yes, we have clients who want to integrate with the Rich Media Processor from legacy apps) suite coming out last week, I felt it necessary to put
some documentation together... internally we've been using FlexWiki
sporadically to document what's happening development-wise, iteration
feature sets etc. So It made sense to release our documentation on the
platform, and offer our clients that ability to augment the
documentation where appropriate.
Mixed Reactions
Wiki's get mixed reactions from a lot of developers - some love
them, others loathe them. I think it's generally related to two
problems:
- Lack of refactoring
- Ignoring beautification
A wiki is a living document, its structure should develop in-line
with your understanding on the topics - this includes revisiting old
topics, pulling content and moving it into new topics etc. If it
attempts to document a product then it must be aligned with releases,
otherwise you will forever be chasing your tale... If you can't get
commitment to this time allocation from management, just don't even
bother.
Stale documentation is often worse then no documentation.
Second to that, if the wiki is clunky, poorly formatted,
disorganised and generally lacking in beauty... Then it's not a
compelling resource for consumers - getting a wiki clean, well
organised and aligned with the rest of your web branding seems to go a
long way towards encouraging use.
Goodbye FlexWiki
We've been using FlexWiki partly through a loyalty to the .Net
platform (http://www.flexwiki.com/) and because internally it's what we
feel most comfortable with when it comes to have to modify or extend
products but the project has stalled for now and just doesn't reach
our needs for a commercially capable collaboration tool... (for
instance it doesn't support attachments) ... so I decided to go find a
new wiki... of which there are many... to many you might say!
WikiMatrix to the rescue
At which point I discovered wikimatrix: http://www.wikimatrix.org/ -
What a great little site! Especially there new Wiki Choice Wizard.. In
about 5 minutes I managed to narrow down what I was looking for, and
eventually selected TWiki (http://www.twiki.org/) as our prime
candidate (Confluence also looked very good, but the entry cost didn't
seem justifiable at this point).
Hello TWiki
TWiki does have some pitfalls for a Microsoft-focused house, mainly
that hosting it on windows is possible but going to cause tears before
bed time... luckily they have a debian vmware installation... so we
have avoided all the grief involved with windows, and gained a tasty
performance bonus over running it on windows (Because the project would
have required the cygwin tools & apache for windows... not
necessarily a high-performance combination)
The second best thing since sliced bread
VMWare server being free has to be probably the best thing since
sliced bread (Though I guess unbundling supersedes that for most IT
people in NZ of late) - as we're seeing a host of Linux based products
being released as pre-configured VM's - suitable as drop in "software
appliances" - with a lot less support problems then the normal process
of installing Linux onto a virtual machine and setting up the software
itself... and Often the memory foot print of the Linux distro + product
is half that of an empty windows 2003 standard install, before you've
deployed any applications onto it.
So within 15 minutes I had downloaded the 220mb virtual image,
booted it up and started editing wiki documents... It's not all quite
that easy though, you still need to get your hands dirty doing a little
shell based configuration if you want to securely host it on the web -
but it's all pretty painless especially if youve dabbled with Linux
in the past.
As for TWiki itself - so far it seems very very good, my only
dislike is some of the wiki-text conventions it uses, such as the
elaborate header mark-up... though FlexWiki was no better - why they
couldn't use the Confluence style mark-up of "h1. " through "h6." I'll
never know still the wysiwyg editor takes away most of the mark-up
pain for new users.
I've managed to avoid doing any Kriss Kross "wickety whack" references for the whole post too - be grateful ;o)
 Tuesday, November 02, 2004
First blog entry, part content, part test.
© Copyright 2010 Alex Henderson
Theme design by Bryan Bell
newtelligence dasBlog 2.3.9074.18820  | Page rendered at Sunday, August 01, 2010 9:21:32 AM (New Zealand Standard Time, UTC+12:00)
|
Search
FeedCount
Tags...
Who am I?

|
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited
"Self Confessed Coding Junky for 15 years"
|
 |
| |
| Mobile: |
+64-21-402-969 |
| Email: |
bittercoder 'at' gmail 'dot' com |
| MSN: |
bittercoder_nz@hotmail |
| Skype: |
alex.devdefined |
Navigation
On this page....
Blogs I read by New Zealanders...
Blogs I read on Castle...
BlogMap
Del.icio.us
Wishlists
|