Sunday, July 20, 2008

Facebook login WTF

Yesterday I was about to log into Facebook and I noticed it was taking too long to load the page... I opened Firebug and saw this:

 

facebook_login

 

Wow. Nice stairs, but it really hurts performance.

Tuesday, July 15, 2008

Castle Facility for SolrSharp

Some months ago I wrote SolrNet, an interface to Solr, mainly because I thought SolrSharp (the standard Solr interface for .net) was too verbose and IoC-unfriendly. I still think that way, but I always wondered what it would take to integrate it to Windsor (or any other IoC container, for that matter).

And the answer is... 241 lines of code (as per "wc -l *.cs"). That's it. That's all it took to write some interfaces and adapters and then wrap them in a Castle facility. That should teach me to try a bit harder next time! :-)

SolrNet was designed with IoC in mind, so integration is just a matter of registering a component:

<component id="solr" service="SolrNet.ISolrOperations`1, SolrNet" type="SolrNet.SolrServer`1, SolrNet">
    <parameters>
        <serverURL>http://localhost:8983/solr</serverURL>
    </parameters>
</component>

Code is here. Note that it's just a proof of concept, I barely tested it!

Monday, July 14, 2008

Y-combinator and LINQ

Today I finally found an excuse to use Wes Dyer's implementation of the Y-combinator in C#:

public delegate Func<A, R> Recursive<A, R>(Recursive<A, R> r)

public static Func<A, R> Y<A, R>(Func<Func<A, R>, Func<A, R>> f) {
Recursive<A, R> rec = r => a => f(r(r))(a);
return rec(rec);
}

I used it to recursively get all the files in a given directory, in a one-liner:
var RecGetFiles = Y<string, IEnumerable<string>>(f => d => Directory.GetFiles(d).Concat(Directory.GetDirectories(d).SelectMany(f)))
Nice, isn't it? Sample usage:
foreach (var f in RecGetFiles(Directory.GetCurrentDirectory()))
Console.WriteLine(f);

It's probably not a good idea, though, to use this in production code, as it's not really necessary (just use regular recursion) and it harms readability.

A few less strings in MonoRail


In the same spirit as my previous post, I wrote a couple of extensions methods to avoid strings when redirecting in Castle MonoRail.
Let's say you have this controller:
public class HomeController : SmartDispatcherController
{
public void Index()
{
}

public void SaveInformation(String name, int age, DateTime dob)
{
// work work work

// Send the user back to the index
RedirectToAction("index");
}
}

Now you can write the redirect like this:

this.RedirectToAction(c => c.Index());

It also works with parameters, i.e. if you have an action like this:

public void Index(int a) {}

you can do:

this.RedirectToAction(c => Index(1));

and it will redirect to /home/index.castle?a=1 (or whatever extension you're using)

It even works with objects and [DataBind] (with some limitations, see below):

public class Properties {
public int SomeValue { get; set; }
}

public class SmartTest2Controller : SmartDispatcherController {
public void DataBinding([DataBind("prefi")] Properties prop) {}
public void Index() {
this.RedirectToAction(c => c.DataBinding(new Properties {SomeValue = 22}));
}
}

Which will redirect to /SmartTest2/DataBinding.castle?prefi.SomeValue=22

There's also support for [ARDataBind] and [ARFetch]:

    public class ARController : ARSmartDispatcherController {
public void Index() {
this.RedirectToAction(c => c.ARFetchAction(new Entity { PK = 5, Name = "Robert Duvall" }));
this.RedirectToAction(c => c.ARAction(new Entity { PK = 4, Name = "John Q" }));
}
public void ARAction([ARDataBind("pre")] Entity e) {}
public void ARFetchAction([ARFetch("pre")] Entity e) { }
}

Which would respectively redirect to /AR/ARFetchAction.castle?pre=5 and /AR/ARAction.castle?pre.PK=4&pre.Name=John+Q
(I was watching John Q while writing this :-) )

ActiveRecord support is implemented in another assembly, to cleanly separate the dependencies. When using the ActiveRecord extensions, you have to initialize it in your Application_Start():

Setup.ForAll(new DefaultExtensionsProvider {ExtUtils = new ARUtils()});
This instructs the extension methods to use the ActiveRecord helpers.

Code is here, let me know your opinion...

Caveats / limitations (for now):
  • Doesn't work with nested object databinding
  • Doesn't work with arrays of objects
  • Works on Castle RC3. Trunk has been refactored a lot regarding controllers since RC3, so this code would have to be adapted (extending IRedirectSupport instead of Controller and such)

UPDATE 5/16/2009: I just found out there already was a similar project on castle contrib.